mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 01:51:12 -05:00
Refactor: Implement desktop layout modernization
This commit is contained in:
@@ -244,7 +244,7 @@ export function AccountProfileTab() {
|
|||||||
const isDeactivated = profile?.deactivated || false;
|
const isDeactivated = profile?.deactivated || false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
{/* Deletion Status Banner */}
|
{/* Deletion Status Banner */}
|
||||||
{deletionRequest && (
|
{deletionRequest && (
|
||||||
<DeletionStatusBanner
|
<DeletionStatusBanner
|
||||||
@@ -253,9 +253,15 @@ export function AccountProfileTab() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Profile Picture + Account Info Grid */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
{/* Profile Picture */}
|
{/* Profile Picture */}
|
||||||
<div className="space-y-4">
|
<Card>
|
||||||
<h3 className="text-lg font-medium">Profile Picture</h3>
|
<CardHeader>
|
||||||
|
<CardTitle>Profile Picture</CardTitle>
|
||||||
|
<CardDescription>Upload your profile picture</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
<PhotoUpload
|
<PhotoUpload
|
||||||
variant="avatar"
|
variant="avatar"
|
||||||
maxFiles={1}
|
maxFiles={1}
|
||||||
@@ -267,11 +273,72 @@ export function AccountProfileTab() {
|
|||||||
handleError(new Error(error), { action: 'Upload avatar' });
|
handleError(new Error(error), { action: 'Upload avatar' });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Account Information */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Account Information</CardTitle>
|
||||||
|
<CardDescription>View your account details</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
{pendingEmail && (
|
||||||
|
<EmailChangeStatus
|
||||||
|
currentEmail={user?.email || ''}
|
||||||
|
pendingEmail={pendingEmail}
|
||||||
|
onCancel={() => setShowCancelEmailDialog(true)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="p-4 bg-muted/50 rounded-lg space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex-1">
|
||||||
|
<p className="text-sm font-medium">Email Address</p>
|
||||||
|
<div className="flex items-center gap-2 mt-1">
|
||||||
|
<p className="text-sm text-muted-foreground">{user?.email}</p>
|
||||||
|
{pendingEmail ? (
|
||||||
|
<Badge variant="secondary" className="bg-blue-500/10 text-blue-500 border-blue-500/20 text-xs">
|
||||||
|
Change Pending
|
||||||
|
</Badge>
|
||||||
|
) : user?.email_confirmed_at ? (
|
||||||
|
<Badge variant="secondary" className="text-xs">Verified</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline" className="text-xs">Pending Verification</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setShowEmailDialog(true)}
|
||||||
|
disabled={!!pendingEmail}
|
||||||
|
>
|
||||||
|
<Mail className="w-4 h-4 mr-2" />
|
||||||
|
Change
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium">Account Created</p>
|
||||||
|
<p className="text-sm text-muted-foreground mt-1">
|
||||||
|
{profile?.created_at ? new Date(profile.created_at).toLocaleDateString() : 'N/A'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Profile Information */}
|
{/* Profile Information */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Profile Information</CardTitle>
|
||||||
|
<CardDescription>Update your public profile details</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||||
<h3 className="text-lg font-medium">Profile Information</h3>
|
<h3 className="text-lg font-medium">Profile Information</h3>
|
||||||
|
|
||||||
@@ -419,60 +486,31 @@ export function AccountProfileTab() {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<Separator />
|
{/* Danger Zone */}
|
||||||
|
<Card className="border-destructive/50">
|
||||||
{/* Account Information */}
|
<CardHeader>
|
||||||
<div className="space-y-4">
|
<CardTitle className="text-destructive">Danger Zone</CardTitle>
|
||||||
<h3 className="text-lg font-medium">Account Information</h3>
|
<CardDescription>Irreversible account actions</CardDescription>
|
||||||
<div className="space-y-4">
|
</CardHeader>
|
||||||
{pendingEmail && (
|
<CardContent>
|
||||||
<EmailChangeStatus
|
|
||||||
currentEmail={user?.email || ''}
|
|
||||||
pendingEmail={pendingEmail}
|
|
||||||
onCancel={() => setShowCancelEmailDialog(true)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="p-4 bg-muted/50 rounded-lg space-y-4">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="flex-1">
|
|
||||||
<p className="text-sm font-medium">Email Address</p>
|
|
||||||
<div className="flex items-center gap-2 mt-1">
|
|
||||||
<p className="text-sm text-muted-foreground">{user?.email}</p>
|
|
||||||
{pendingEmail ? (
|
|
||||||
<Badge variant="secondary" className="bg-blue-500/10 text-blue-500 border-blue-500/20 text-xs">
|
|
||||||
Change Pending
|
|
||||||
</Badge>
|
|
||||||
) : user?.email_confirmed_at ? (
|
|
||||||
<Badge variant="secondary" className="text-xs">Verified</Badge>
|
|
||||||
) : (
|
|
||||||
<Badge variant="outline" className="text-xs">Pending Verification</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="destructive"
|
||||||
size="sm"
|
onClick={() => setShowDeletionDialog(true)}
|
||||||
onClick={() => setShowEmailDialog(true)}
|
disabled={!!deletionRequest}
|
||||||
disabled={!!pendingEmail}
|
|
||||||
>
|
>
|
||||||
<Mail className="w-4 h-4 mr-2" />
|
<Trash2 className="w-4 h-4 mr-2" />
|
||||||
Change Email
|
Delete Account
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
{deletionRequest && (
|
||||||
|
<p className="text-sm text-muted-foreground mt-2">
|
||||||
<Separator />
|
Account deletion already in progress
|
||||||
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium">Account Created</p>
|
|
||||||
<p className="text-sm text-muted-foreground mt-1">
|
|
||||||
{profile?.created_at ? new Date(profile.created_at).toLocaleDateString() : 'N/A'}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</CardContent>
|
||||||
</div>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Email Change Dialog */}
|
{/* Email Change Dialog */}
|
||||||
{user && (
|
{user && (
|
||||||
@@ -486,29 +524,6 @@ export function AccountProfileTab() {
|
|||||||
|
|
||||||
{/* Cancel Email Change Dialog */}
|
{/* Cancel Email Change Dialog */}
|
||||||
<AlertDialog open={showCancelEmailDialog} onOpenChange={setShowCancelEmailDialog}>
|
<AlertDialog open={showCancelEmailDialog} onOpenChange={setShowCancelEmailDialog}>
|
||||||
<AlertDialogContent>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>Cancel Email Change?</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
This will cancel your pending email change to <strong>{pendingEmail}</strong>.
|
|
||||||
Your email will remain as <strong>{user?.email}</strong>.
|
|
||||||
You can start a new email change request at any time.
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogCancel disabled={cancellingEmail}>Keep Change</AlertDialogCancel>
|
|
||||||
<AlertDialogAction
|
|
||||||
onClick={handleCancelEmailChange}
|
|
||||||
disabled={cancellingEmail}
|
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
||||||
>
|
|
||||||
{cancellingEmail ? 'Cancelling...' : 'Yes, Cancel Change'}
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
{/* Danger Zone */}
|
{/* Danger Zone */}
|
||||||
<Card className="border-destructive">
|
<Card className="border-destructive">
|
||||||
@@ -538,6 +553,28 @@ export function AccountProfileTab() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Cancel Email Change?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
This will cancel your pending email change to <strong>{pendingEmail}</strong>.
|
||||||
|
Your email will remain as <strong>{user?.email}</strong>.
|
||||||
|
You can start a new email change request at any time.
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel disabled={cancellingEmail}>Keep Change</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
onClick={handleCancelEmailChange}
|
||||||
|
disabled={cancellingEmail}
|
||||||
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
|
>
|
||||||
|
{cancellingEmail ? 'Cancelling...' : 'Yes, Cancel Change'}
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
{/* Account Deletion Dialog */}
|
{/* Account Deletion Dialog */}
|
||||||
<AccountDeletionDialog
|
<AccountDeletionDialog
|
||||||
open={showDeletionDialog}
|
open={showDeletionDialog}
|
||||||
|
|||||||
@@ -281,16 +281,16 @@ export function DataExportTab() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
|
{/* Statistics + Recent Activity Grid */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
{/* Personal Statistics */}
|
{/* Personal Statistics */}
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<BarChart3 className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Personal Statistics</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<BarChart3 className="w-5 h-5" />
|
||||||
|
<CardTitle>Personal Statistics</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Your activity and contribution statistics on ThrillWiki
|
Your activity and contribution statistics on ThrillWiki
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -334,20 +334,136 @@ export function DataExportTab() {
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
{/* Export Your Data */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Download className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Export Your Data</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{/* Account Activity */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Download Your Data</CardTitle>
|
<div className="flex items-center gap-2">
|
||||||
|
<Activity className="w-5 h-5" />
|
||||||
|
<CardTitle>Account Activity</CardTitle>
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
Recent account activity and changes
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-6">
|
||||||
|
{rateLimited && nextAvailableAt && (
|
||||||
|
<div className="flex items-start gap-3 p-4 border border-yellow-500/20 bg-yellow-500/10 rounded-lg">
|
||||||
|
<Clock className="w-5 h-5 text-yellow-500 mt-0.5" />
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="text-sm font-medium">Rate Limited</p>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
You can export your data once per hour. Next export available at{' '}
|
||||||
|
{formatDate(nextAvailableAt)}.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Choose what to include in your export:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="include_reviews">Include Reviews</Label>
|
||||||
|
<Switch
|
||||||
|
id="include_reviews"
|
||||||
|
checked={exportOptions.include_reviews}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
setExportOptions({ ...exportOptions, include_reviews: checked })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="include_lists">Include Lists</Label>
|
||||||
|
<Switch
|
||||||
|
id="include_lists"
|
||||||
|
checked={exportOptions.include_lists}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
setExportOptions({ ...exportOptions, include_lists: checked })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="include_activity_log">Include Activity Log</Label>
|
||||||
|
<Switch
|
||||||
|
id="include_activity_log"
|
||||||
|
checked={exportOptions.include_activity_log}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
setExportOptions({ ...exportOptions, include_activity_log: checked })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="include_preferences">Include Preferences</Label>
|
||||||
|
<Switch
|
||||||
|
id="include_preferences"
|
||||||
|
checked={exportOptions.include_preferences}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
setExportOptions({ ...exportOptions, include_preferences: checked })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-start gap-3 p-4 border rounded-lg">
|
||||||
|
<AlertCircle className="w-5 h-5 text-blue-500 mt-0.5" />
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="text-sm font-medium">GDPR Compliance</p>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
This export includes all personal data we store about you. You can use this for backup purposes or to migrate to another service.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={handleDataExport}
|
||||||
|
disabled={exporting || rateLimited}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<Download className="w-4 h-4 mr-2" />
|
||||||
|
{exporting ? 'Exporting Data...' : 'Export My Data'}
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent>
|
||||||
|
{recentActivity.length === 0 ? (
|
||||||
|
<p className="text-sm text-muted-foreground text-center py-4">
|
||||||
|
No recent activity to display
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-4">
|
||||||
|
{recentActivity.map((activity) => (
|
||||||
|
<div key={activity.id} className="flex items-start gap-3 pb-4 border-b last:border-0 last:pb-0">
|
||||||
|
<Activity className="w-4 h-4 text-muted-foreground mt-1" />
|
||||||
|
<div className="flex-1 space-y-1">
|
||||||
|
<p className="text-sm font-medium">
|
||||||
|
{formatActionName(activity.action)}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{formatDate(activity.created_at)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Export Your Data - Full Width */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Download className="w-5 h-5" />
|
||||||
|
<CardTitle>Export Your Data</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Export all your ThrillWiki data in JSON format. This includes your profile, reviews, lists, and activity history.
|
Export all your ThrillWiki data in JSON format. This includes your profile, reviews, lists, and activity history.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -439,47 +555,5 @@ export function DataExportTab() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
{/* Account Activity */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Activity className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Account Activity</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardDescription>
|
|
||||||
Recent account activity and changes
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
{recentActivity.length === 0 ? (
|
|
||||||
<p className="text-sm text-muted-foreground text-center py-4">
|
|
||||||
No recent activity to display
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<div className="space-y-4">
|
|
||||||
{recentActivity.map((activity) => (
|
|
||||||
<div key={activity.id} className="flex items-start gap-3 pb-4 border-b last:border-0 last:pb-0">
|
|
||||||
<Activity className="w-4 h-4 text-muted-foreground mt-1" />
|
|
||||||
<div className="flex-1 space-y-1">
|
|
||||||
<p className="text-sm font-medium">
|
|
||||||
{formatActionName(activity.action)}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
{formatDate(activity.created_at)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { Card, CardContent, CardDescription, CardHeader } from '@/components/ui/card';
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
@@ -304,16 +304,17 @@ export function LocationTab() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||||
<div className="space-y-4">
|
{/* Location Settings + Personal Information Grid */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<MapPin className="w-5 h-5" />
|
{/* Location Settings */}
|
||||||
<h3 className="text-lg font-medium">Location Settings</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<MapPin className="w-5 h-5" />
|
||||||
|
<CardTitle>Location Settings</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Set your location for better personalized content and timezone display.
|
Set your location for better personalized content and timezone display.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -425,18 +426,14 @@ export function LocationTab() {
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Calendar className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Personal Information</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{/* Personal Information */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Calendar className="w-5 h-5" />
|
||||||
|
<CardTitle>Personal Information</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Optional personal information that can be displayed on your profile.
|
Optional personal information that can be displayed on your profile.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -462,16 +459,15 @@ export function LocationTab() {
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator />
|
{/* Unit Preferences + Accessibility Options Grid */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<div className="space-y-4">
|
{/* Unit Preferences */}
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Ruler className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Units & Measurements</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Ruler className="w-5 h-5" />
|
||||||
|
<CardTitle>Units & Measurements</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Choose your preferred measurement system for displaying distances, speeds, and other measurements.
|
Choose your preferred measurement system for displaying distances, speeds, and other measurements.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -499,18 +495,14 @@ export function LocationTab() {
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Accessibility className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Accessibility Options</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{/* Accessibility Options */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Accessibility className="w-5 h-5" />
|
||||||
|
<CardTitle>Accessibility Options</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Customize the interface to meet your accessibility needs.
|
Customize the interface to meet your accessibility needs.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -564,6 +556,7 @@ export function LocationTab() {
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Save Button */}
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button type="submit" disabled={saving}>
|
<Button type="submit" disabled={saving}>
|
||||||
{saving ? 'Saving...' : 'Save Settings'}
|
{saving ? 'Saving...' : 'Save Settings'}
|
||||||
|
|||||||
@@ -239,6 +239,9 @@ export function NotificationsTab() {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Notification Channels + Frequency Grid */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
|
{/* Notification Channels */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Notification Channels</CardTitle>
|
<CardTitle>Notification Channels</CardTitle>
|
||||||
@@ -301,6 +304,7 @@ export function NotificationsTab() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
{/* Notification Frequency */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Notification Frequency</CardTitle>
|
<CardTitle>Notification Frequency</CardTitle>
|
||||||
@@ -359,7 +363,9 @@ export function NotificationsTab() {
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Workflow Preferences - Full Width */}
|
||||||
{Object.keys(groupedTemplates).map((category) => (
|
{Object.keys(groupedTemplates).map((category) => (
|
||||||
<Card key={category}>
|
<Card key={category}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -234,17 +234,17 @@ export function PrivacyTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||||
|
{/* Profile Visibility + Activity & Content Grid */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
{/* Profile Visibility */}
|
{/* Profile Visibility */}
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Eye className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Profile Visibility</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Eye className="w-5 h-5" />
|
||||||
|
<CardTitle>Profile Visibility</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Control who can see your profile and personal information.
|
Control who can see your profile and personal information.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -363,19 +363,14 @@ export function PrivacyTab() {
|
|||||||
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
{/* Activity & Content */}
|
{/* Activity & Content */}
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Shield className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Activity & Content</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Shield className="w-5 h-5" />
|
||||||
|
<CardTitle>Activity & Content</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Control the visibility of your activities and content.
|
Control the visibility of your activities and content.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -407,17 +402,13 @@ export function PrivacyTab() {
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
{/* Search & Discovery */}
|
{/* Search & Discovery */}
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Search className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Search & Discovery</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Search className="w-5 h-5" />
|
||||||
|
<CardTitle>Search & Discovery</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Control how others can find and discover your profile.
|
Control how others can find and discover your profile.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -437,19 +428,14 @@ export function PrivacyTab() {
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
{/* Blocked Users */}
|
{/* Blocked Users */}
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<UserX className="w-5 h-5" />
|
|
||||||
<h3 className="text-lg font-medium">Blocked Users</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<UserX className="w-5 h-5" />
|
||||||
|
<CardTitle>Blocked Users</CardTitle>
|
||||||
|
</div>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Manage users you have blocked from interacting with you.
|
Manage users you have blocked from interacting with you.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@@ -458,7 +444,6 @@ export function PrivacyTab() {
|
|||||||
<BlockedUsers />
|
<BlockedUsers />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Save Button */}
|
{/* Save Button */}
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export default function UserSettings() {
|
|||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<Header />
|
<Header />
|
||||||
<div className="container mx-auto px-4 py-8">
|
<div className="container mx-auto px-4 py-8">
|
||||||
<div className="max-w-6xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center gap-3 mb-8">
|
<div className="flex items-center gap-3 mb-8">
|
||||||
<Settings className="w-8 h-8 text-primary" />
|
<Settings className="w-8 h-8 text-primary" />
|
||||||
@@ -118,19 +118,9 @@ export default function UserSettings() {
|
|||||||
<TabsContent
|
<TabsContent
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
value={tab.id}
|
value={tab.id}
|
||||||
className="space-y-6 focus-visible:outline-none"
|
className="focus-visible:outline-none"
|
||||||
>
|
>
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="flex items-center gap-2">
|
|
||||||
<tab.icon className="w-5 h-5" />
|
|
||||||
{tab.label}
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<Component />
|
<Component />
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user