-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30 from PoulavBhowmick03/main
Added a settings page, settings route with REST functionality and migrated the db
- Loading branch information
Showing
16 changed files
with
763 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,12 @@ | ||
'use client'; | ||
|
||
import { TooltipProvider } from '@/components/ui/tooltip'; | ||
import { ClerkProvider } from '@clerk/nextjs'; | ||
|
||
export default function Providers({ children }: { children: React.ReactNode }) { | ||
return <TooltipProvider>{children}</TooltipProvider>; | ||
return ( | ||
<ClerkProvider> | ||
<TooltipProvider>{children}</TooltipProvider> | ||
</ClerkProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,188 @@ | ||
import { | ||
Card, | ||
CardContent, | ||
CardDescription, | ||
CardHeader, | ||
CardTitle | ||
} from '@/components/ui/card'; | ||
'use client' | ||
|
||
import { useEffect, useState } from 'react' | ||
import { useRouter } from 'next/navigation' | ||
import { useUser } from '@clerk/nextjs' | ||
import axios from 'axios' | ||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" | ||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" | ||
import { Input } from "@/components/ui/input" | ||
import { Button } from "@/components/ui/button" | ||
import { Label } from "@/components/ui/label" | ||
import { AlertCircle, User, Lock, Trash2 } from 'lucide-react' | ||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" | ||
|
||
interface UserData { | ||
id: number | ||
username: string | ||
email: string | ||
theme: string | ||
role: string | ||
} | ||
|
||
export default function SettingsPage() { | ||
const { user } = useUser() | ||
const router = useRouter() | ||
|
||
const [userData, setUserData] = useState<UserData | null>(null) | ||
const [loading, setLoading] = useState<boolean>(true) | ||
const [error, setError] = useState<string | null>(null) | ||
|
||
useEffect(() => { | ||
const fetchUserData = async () => { | ||
try { | ||
const response = await axios.get('/api/settings') | ||
setUserData(response.data.data) | ||
} catch (err: any) { | ||
setError(err.response?.data?.error || 'Failed to fetch user data') | ||
} finally { | ||
setLoading(false) | ||
} | ||
} | ||
|
||
fetchUserData() | ||
}, []) | ||
|
||
const handleUpdateProfile = async (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault() | ||
setError(null) | ||
const form = e.currentTarget | ||
const formData = new FormData(form) | ||
const username = formData.get('username') as string | ||
const email = formData.get('email') as string | ||
|
||
try { | ||
const response = await axios.put('/api/settings', { username, email }) | ||
setUserData((prev) => prev ? { ...prev, username, email } : prev) | ||
alert(response.data.message) | ||
} catch (err: any) { | ||
setError(err.response?.data?.error || 'Failed to update profile') | ||
} | ||
} | ||
|
||
const handleChangePassword = async (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault() | ||
setError(null) | ||
const form = e.currentTarget | ||
const formData = new FormData(form) | ||
const currentPassword = formData.get('currentPassword') as string | ||
const newPassword = formData.get('newPassword') as string | ||
|
||
try { | ||
const response = await axios.post('/api/settings', { currentPassword, newPassword }) | ||
alert(response.data.message) | ||
form.reset() | ||
} catch (err: any) { | ||
setError(err.response?.data?.error || 'Failed to change password') | ||
} | ||
} | ||
|
||
const handleDeleteAccount = async () => { | ||
const confirmDelete = confirm('Are you sure you want to delete your account? This action cannot be undone.') | ||
if (!confirmDelete) return | ||
|
||
const password = prompt('Please enter your password to confirm deletion:') | ||
if (!password) { | ||
alert('Password is required to delete your account.') | ||
return | ||
} | ||
|
||
try { | ||
const response = await axios.delete('/api/settings', { data: { password } }) | ||
alert(response.data.message) | ||
router.push('/') // Redirect to homepage after deletion | ||
} catch (err: any) { | ||
setError(err.response?.data?.error || 'Failed to delete account') | ||
} | ||
} | ||
|
||
if (loading) return <div className="flex justify-center items-center h-screen">Loading...</div> | ||
if (!userData) return <div className="flex justify-center items-center h-screen">No user data available.</div> | ||
|
||
return ( | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Settings</CardTitle> | ||
<CardDescription>Settings items.</CardDescription> | ||
</CardHeader> | ||
<CardContent></CardContent> | ||
</Card> | ||
); | ||
} | ||
<div className="container mx-auto p-4 max-w-4xl"> | ||
<h1 className="text-3xl font-bold mb-6">Account Settings</h1> | ||
|
||
{error && ( | ||
<Alert variant="destructive" className="mb-6"> | ||
<AlertCircle className="h-4 w-4" /> | ||
<AlertTitle>Error</AlertTitle> | ||
<AlertDescription>{error}</AlertDescription> | ||
</Alert> | ||
)} | ||
|
||
<Tabs defaultValue="profile" className="space-y-6"> | ||
<TabsList className="grid w-full grid-cols-3"> | ||
<TabsTrigger value="profile">Profile</TabsTrigger> | ||
<TabsTrigger value="security">Security</TabsTrigger> | ||
<TabsTrigger value="danger">Danger Zone</TabsTrigger> | ||
</TabsList> | ||
|
||
<TabsContent value="profile"> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Profile Information</CardTitle> | ||
<CardDescription>Update your account profile information here.</CardDescription> | ||
</CardHeader> | ||
<form onSubmit={handleUpdateProfile}> | ||
<CardContent className="space-y-4"> | ||
<div className="space-y-2"> | ||
<Label htmlFor="username">Username</Label> | ||
<Input id="username" name="username" defaultValue={userData.username} required /> | ||
</div> | ||
<div className="space-y-2"> | ||
<Label htmlFor="email">Email</Label> | ||
<Input id="email" name="email" type="email" defaultValue={userData.email} required /> | ||
</div> | ||
</CardContent> | ||
<CardFooter> | ||
<Button type="submit">Update Profile</Button> | ||
</CardFooter> | ||
</form> | ||
</Card> | ||
</TabsContent> | ||
|
||
<TabsContent value="security"> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Change Password</CardTitle> | ||
<CardDescription>Ensure your account is using a long, random password to stay secure.</CardDescription> | ||
</CardHeader> | ||
<form onSubmit={handleChangePassword}> | ||
<CardContent className="space-y-4"> | ||
<div className="space-y-2"> | ||
<Label htmlFor="currentPassword">Current Password</Label> | ||
<Input id="currentPassword" name="currentPassword" type="password" required /> | ||
</div> | ||
<div className="space-y-2"> | ||
<Label htmlFor="newPassword">New Password</Label> | ||
<Input id="newPassword" name="newPassword" type="password" required /> | ||
</div> | ||
</CardContent> | ||
<CardFooter> | ||
<Button type="submit">Change Password</Button> | ||
</CardFooter> | ||
</form> | ||
</Card> | ||
</TabsContent> | ||
|
||
<TabsContent value="danger"> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Delete Account</CardTitle> | ||
<CardDescription>Once you delete your account, there is no going back. Please be certain.</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<p className="text-sm text-muted-foreground mb-4"> | ||
Deleting your account will remove all of your information from our database. This cannot be undone. | ||
</p> | ||
<Button variant="destructive" onClick={handleDeleteAccount}> | ||
<Trash2 className="mr-2 h-4 w-4" /> Delete Account | ||
</Button> | ||
</CardContent> | ||
</Card> | ||
</TabsContent> | ||
</Tabs> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.