@djangocfg/layouts 2.1.97 → 2.1.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.100",
|
|
4
4
|
"description": "Simple, straightforward layout components for Next.js - import and use with props",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -92,16 +92,16 @@
|
|
|
92
92
|
"check": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
-
"@djangocfg/api": "^2.1.
|
|
96
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
97
|
-
"@djangocfg/ui-core": "^2.1.
|
|
98
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
99
|
-
"@djangocfg/ui-tools": "^2.1.
|
|
95
|
+
"@djangocfg/api": "^2.1.100",
|
|
96
|
+
"@djangocfg/centrifugo": "^2.1.100",
|
|
97
|
+
"@djangocfg/ui-core": "^2.1.100",
|
|
98
|
+
"@djangocfg/ui-nextjs": "^2.1.100",
|
|
99
|
+
"@djangocfg/ui-tools": "^2.1.100",
|
|
100
100
|
"@hookform/resolvers": "^5.2.0",
|
|
101
101
|
"consola": "^3.4.2",
|
|
102
102
|
"lucide-react": "^0.545.0",
|
|
103
103
|
"moment": "^2.30.1",
|
|
104
|
-
"next": ">=
|
|
104
|
+
"next": ">=16.0.0",
|
|
105
105
|
"p-retry": "^7.0.0",
|
|
106
106
|
"react": "^19.1.0",
|
|
107
107
|
"react-dom": "^19.1.0",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"uuid": "^11.1.0"
|
|
120
120
|
},
|
|
121
121
|
"devDependencies": {
|
|
122
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
122
|
+
"@djangocfg/typescript-config": "^2.1.100",
|
|
123
123
|
"@types/node": "^24.7.2",
|
|
124
124
|
"@types/react": "^19.1.0",
|
|
125
125
|
"@types/react-dom": "^19.1.0",
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
Card, CardContent, CardDescription, CardHeader, CardTitle, Preloader
|
|
10
10
|
} from '@djangocfg/ui-nextjs/components';
|
|
11
11
|
|
|
12
|
-
import { AvatarSection, ProfileForm, TwoFactorSection } from './components';
|
|
12
|
+
import { AvatarSection, DeleteAccountSection, ProfileForm, TwoFactorSection } from './components';
|
|
13
13
|
|
|
14
14
|
interface ProfileLayoutProps {
|
|
15
15
|
// Callbacks
|
|
@@ -27,6 +27,13 @@ interface ProfileLayoutProps {
|
|
|
27
27
|
* @default false
|
|
28
28
|
*/
|
|
29
29
|
enable2FA?: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Enable account deletion section in profile.
|
|
33
|
+
* When true, users can delete their account from their profile.
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
enableDeleteAccount?: boolean;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
const ProfileContent = ({
|
|
@@ -36,6 +43,7 @@ const ProfileContent = ({
|
|
|
36
43
|
showMemberSince = true,
|
|
37
44
|
showLastLogin = true,
|
|
38
45
|
enable2FA = false,
|
|
46
|
+
enableDeleteAccount = true,
|
|
39
47
|
}: ProfileLayoutProps) => {
|
|
40
48
|
const { user, isLoading } = useAuth();
|
|
41
49
|
|
|
@@ -116,6 +124,9 @@ const ProfileContent = ({
|
|
|
116
124
|
|
|
117
125
|
{/* Two-Factor Authentication Section */}
|
|
118
126
|
{enable2FA && <TwoFactorSection />}
|
|
127
|
+
|
|
128
|
+
{/* Delete Account Section */}
|
|
129
|
+
{enableDeleteAccount && <DeleteAccountSection />}
|
|
119
130
|
</div>
|
|
120
131
|
</div>
|
|
121
132
|
);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { AlertTriangle, Loader2, Trash2 } from 'lucide-react';
|
|
4
|
+
import React, { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import { useAuth, useDeleteAccount } from '@djangocfg/api/auth';
|
|
7
|
+
import {
|
|
8
|
+
Alert,
|
|
9
|
+
AlertDescription,
|
|
10
|
+
Button,
|
|
11
|
+
Card,
|
|
12
|
+
CardContent,
|
|
13
|
+
CardDescription,
|
|
14
|
+
CardHeader,
|
|
15
|
+
CardTitle,
|
|
16
|
+
Dialog,
|
|
17
|
+
DialogContent,
|
|
18
|
+
DialogDescription,
|
|
19
|
+
DialogFooter,
|
|
20
|
+
DialogHeader,
|
|
21
|
+
DialogTitle,
|
|
22
|
+
Input,
|
|
23
|
+
} from '@djangocfg/ui-nextjs/components';
|
|
24
|
+
|
|
25
|
+
const CONFIRMATION_TEXT = 'DELETE';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Delete Account section for ProfileLayout.
|
|
29
|
+
* Allows users to permanently delete their account.
|
|
30
|
+
*/
|
|
31
|
+
export const DeleteAccountSection: React.FC = () => {
|
|
32
|
+
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
|
33
|
+
const [confirmationInput, setConfirmationInput] = useState('');
|
|
34
|
+
const { logout } = useAuth();
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
isLoading,
|
|
38
|
+
error,
|
|
39
|
+
deleteAccount,
|
|
40
|
+
clearError,
|
|
41
|
+
} = useDeleteAccount();
|
|
42
|
+
|
|
43
|
+
const handleDeleteClick = () => {
|
|
44
|
+
setShowDeleteDialog(true);
|
|
45
|
+
setConfirmationInput('');
|
|
46
|
+
clearError();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const handleDeleteConfirm = async () => {
|
|
50
|
+
const result = await deleteAccount();
|
|
51
|
+
if (result.success) {
|
|
52
|
+
setShowDeleteDialog(false);
|
|
53
|
+
// Perform logout after successful deletion
|
|
54
|
+
await logout();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleDeleteCancel = () => {
|
|
59
|
+
setShowDeleteDialog(false);
|
|
60
|
+
setConfirmationInput('');
|
|
61
|
+
clearError();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const isConfirmationValid = confirmationInput.toUpperCase() === CONFIRMATION_TEXT;
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
<Card className="bg-card/50 backdrop-blur-sm border-red-200 dark:border-red-800/50">
|
|
69
|
+
<CardHeader>
|
|
70
|
+
<CardTitle className="flex items-center gap-2 text-red-600 dark:text-red-400">
|
|
71
|
+
<Trash2 className="w-5 h-5" />
|
|
72
|
+
Delete Account
|
|
73
|
+
</CardTitle>
|
|
74
|
+
<CardDescription>
|
|
75
|
+
Permanently delete your account and all associated data
|
|
76
|
+
</CardDescription>
|
|
77
|
+
</CardHeader>
|
|
78
|
+
|
|
79
|
+
<CardContent className="space-y-4">
|
|
80
|
+
<Alert variant="destructive" className="bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800">
|
|
81
|
+
<AlertTriangle className="w-4 h-4" />
|
|
82
|
+
<AlertDescription>
|
|
83
|
+
This action is irreversible. Your account will be deactivated and your personal data will be anonymized.
|
|
84
|
+
</AlertDescription>
|
|
85
|
+
</Alert>
|
|
86
|
+
|
|
87
|
+
<div className="flex items-center justify-between p-4 bg-muted/50 rounded-lg">
|
|
88
|
+
<div>
|
|
89
|
+
<p className="font-medium">Delete your account</p>
|
|
90
|
+
<p className="text-sm text-muted-foreground">
|
|
91
|
+
You will lose access to all your data and workspaces
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
<Button
|
|
95
|
+
variant="destructive"
|
|
96
|
+
onClick={handleDeleteClick}
|
|
97
|
+
disabled={isLoading}
|
|
98
|
+
>
|
|
99
|
+
Delete Account
|
|
100
|
+
</Button>
|
|
101
|
+
</div>
|
|
102
|
+
</CardContent>
|
|
103
|
+
</Card>
|
|
104
|
+
|
|
105
|
+
{/* Delete Account Dialog */}
|
|
106
|
+
<Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
|
107
|
+
<DialogContent>
|
|
108
|
+
<DialogHeader>
|
|
109
|
+
<DialogTitle className="flex items-center gap-2 text-red-600">
|
|
110
|
+
<AlertTriangle className="w-5 h-5" />
|
|
111
|
+
Delete Account
|
|
112
|
+
</DialogTitle>
|
|
113
|
+
<DialogDescription>
|
|
114
|
+
This action cannot be undone. This will permanently deactivate your account
|
|
115
|
+
and anonymize your personal data.
|
|
116
|
+
</DialogDescription>
|
|
117
|
+
</DialogHeader>
|
|
118
|
+
|
|
119
|
+
<div className="py-4 space-y-4">
|
|
120
|
+
{error && (
|
|
121
|
+
<Alert variant="destructive">
|
|
122
|
+
<AlertDescription>{error}</AlertDescription>
|
|
123
|
+
</Alert>
|
|
124
|
+
)}
|
|
125
|
+
|
|
126
|
+
<div className="space-y-2">
|
|
127
|
+
<p className="text-sm text-muted-foreground">
|
|
128
|
+
To confirm, type <span className="font-mono font-bold">{CONFIRMATION_TEXT}</span> below:
|
|
129
|
+
</p>
|
|
130
|
+
<Input
|
|
131
|
+
value={confirmationInput}
|
|
132
|
+
onChange={(e) => setConfirmationInput(e.target.value)}
|
|
133
|
+
placeholder={CONFIRMATION_TEXT}
|
|
134
|
+
disabled={isLoading}
|
|
135
|
+
autoComplete="off"
|
|
136
|
+
/>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<DialogFooter>
|
|
141
|
+
<Button
|
|
142
|
+
variant="outline"
|
|
143
|
+
onClick={handleDeleteCancel}
|
|
144
|
+
disabled={isLoading}
|
|
145
|
+
>
|
|
146
|
+
Cancel
|
|
147
|
+
</Button>
|
|
148
|
+
<Button
|
|
149
|
+
variant="destructive"
|
|
150
|
+
onClick={handleDeleteConfirm}
|
|
151
|
+
disabled={isLoading || !isConfirmationValid}
|
|
152
|
+
>
|
|
153
|
+
{isLoading ? (
|
|
154
|
+
<>
|
|
155
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
156
|
+
Deleting...
|
|
157
|
+
</>
|
|
158
|
+
) : (
|
|
159
|
+
'Delete Account'
|
|
160
|
+
)}
|
|
161
|
+
</Button>
|
|
162
|
+
</DialogFooter>
|
|
163
|
+
</DialogContent>
|
|
164
|
+
</Dialog>
|
|
165
|
+
</>
|
|
166
|
+
);
|
|
167
|
+
};
|