Skip to content
Merged

Dev #49

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/integrations/supabase/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ export type Database = {
[_ in never]: never
}
Functions: {
delete_user: {
Args: Record<PropertyKey, never>
Returns: undefined
}
has_role: {
Args: {
_role: Database["public"]["Enums"]["app_role"]
Expand Down
92 changes: 89 additions & 3 deletions src/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@ import { Input } from "@/components/ui/input";
import { toast } from "sonner";
import { supabase } from "@/integrations/supabase/client";
import { Toaster } from "sonner";
import { ArrowLeft, Loader2 } from "lucide-react";
import { Link } from "react-router-dom";
import { ArrowLeft, Loader2, Trash2 } from "lucide-react";
import { Link, useNavigate } from "react-router-dom";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import {
Form,
FormControl,
Expand All @@ -31,8 +42,10 @@ const passwordSchema = z.object({


const Settings = () => {
const { user } = useAuth();
const { user, signOut } = useAuth();
const navigate = useNavigate();
const [isChangingPassword, setIsChangingPassword] = useState(false);
const [isDeletingAccount, setIsDeletingAccount] = useState(false);

const form = useForm<z.infer<typeof passwordSchema>>({
resolver: zodResolver(passwordSchema),
Expand Down Expand Up @@ -77,6 +90,28 @@ const Settings = () => {
}
};

const handleDeleteAccount = async () => {
try {
setIsDeletingAccount(true);

// Call the delete_user RPC function which will delete the user and all related data
const { error } = await supabase.rpc('delete_user');

if (error) {
toast.error("Failed to delete account: " + error.message);
return;
}

toast.success("Account deleted successfully");
await signOut();
navigate("/auth");
} catch (error: any) {
toast.error("Error deleting account: " + error.message);
} finally {
setIsDeletingAccount(false);
}
};

return (
<div className="min-h-screen bg-portfolio-bg pb-12">
<Toaster position="top-center" />
Expand Down Expand Up @@ -177,6 +212,57 @@ const Settings = () => {
</form>
</Form>
</div>

<div className="border-t pt-6">
<h2 className="text-lg font-semibold mb-4 text-destructive">Danger Zone</h2>
<div className="space-y-4">
<div>
<p className="text-sm text-muted-foreground mb-4">
Once you delete your account, there is no going back. All your data including portfolio, projects, and analytics will be permanently deleted.
</p>

<AlertDialog>
<AlertDialogTrigger asChild>
<Button
variant="destructive"
disabled={isDeletingAccount}
>
{isDeletingAccount ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Deleting Account...
</>
) : (
<>
<Trash2 className="mr-2 h-4 w-4" />
Delete Account
</>
)}
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your account
and remove all your data from our servers including your portfolio, projects,
sections, and analytics data.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={handleDeleteAccount}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
Yes, delete my account
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</div>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- Function to delete the current user's account
-- This will cascade delete all related data due to foreign key constraints
CREATE OR REPLACE FUNCTION public.delete_user()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
current_user_id uuid;
BEGIN
-- Get the current user's ID
current_user_id := auth.uid();

-- Ensure user is authenticated
IF current_user_id IS NULL THEN
RAISE EXCEPTION 'Not authenticated';
END IF;

-- Delete the user from auth.users
-- This will cascade delete all related data in public schema tables
DELETE FROM auth.users WHERE id = current_user_id;
END;
$$;