@djangocfg/layouts 2.1.264 → 2.1.267

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.
Files changed (38) hide show
  1. package/README.md +113 -4
  2. package/package.json +19 -18
  3. package/src/hooks/index.ts +1 -1
  4. package/src/hooks/usePathnameWithoutLocale.ts +35 -19
  5. package/src/layouts/AppLayout/AppLayout.tsx +15 -4
  6. package/src/layouts/AuthLayout/components/steps/SetupStep/index.tsx +50 -6
  7. package/src/layouts/ProfileLayout/ProfileLayout.tsx +206 -235
  8. package/src/layouts/ProfileLayout/components/AvatarSection.tsx +2 -3
  9. package/src/layouts/ProfileLayout/components/DeleteAccountSection.tsx +22 -106
  10. package/src/layouts/ProfileLayout/components/EditableField.tsx +15 -10
  11. package/src/layouts/ProfileLayout/components/Section.tsx +1 -1
  12. package/src/layouts/ProfileLayout/components/TwoFactorSection.tsx +255 -215
  13. package/src/layouts/ProfileLayout/context.tsx +108 -16
  14. package/src/layouts/ProfileLayout/index.ts +1 -1
  15. package/src/layouts/PublicLayout/PublicLayout.tsx +18 -0
  16. package/src/layouts/PublicLayout/components/NavActions.tsx +50 -0
  17. package/src/layouts/PublicLayout/components/NavBrand.tsx +26 -0
  18. package/src/layouts/PublicLayout/components/NavDesktopItems.tsx +207 -0
  19. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +1 -1
  20. package/src/layouts/PublicLayout/components/PublicNavbar.tsx +44 -6
  21. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +199 -396
  22. package/src/layouts/PublicLayout/hooks/index.ts +5 -1
  23. package/src/layouts/PublicLayout/hooks/useDropdownMenu.ts +58 -0
  24. package/src/layouts/PublicLayout/hooks/useNavbarScroll.ts +61 -0
  25. package/src/layouts/PublicLayout/hooks/useNavbarViewportVars.ts +46 -0
  26. package/src/layouts/PublicLayout/index.ts +4 -0
  27. package/src/layouts/PublicLayout/navbarTypes.ts +17 -0
  28. package/src/utils/pathMatcher.ts +6 -3
  29. package/src/layouts/ProfileLayout/.claude/.sidecar/activity.jsonl +0 -2
  30. package/src/layouts/ProfileLayout/.claude/.sidecar/history/2026-03-15.md +0 -35
  31. package/src/layouts/ProfileLayout/.claude/.sidecar/review.md +0 -35
  32. package/src/layouts/ProfileLayout/.claude/.sidecar/scan.log +0 -3
  33. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-001.md +0 -18
  34. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-002.md +0 -19
  35. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-003.md +0 -18
  36. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-004.md +0 -18
  37. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-005.md +0 -18
  38. package/src/layouts/ProfileLayout/.claude/.sidecar/usage.json +0 -5
@@ -1,128 +1,44 @@
1
1
  'use client';
2
2
 
3
- import { AlertTriangle, ChevronLeft, Loader2, Trash2 } from 'lucide-react';
4
- import React, { useMemo, useState } from 'react';
3
+ import { Trash2 } from 'lucide-react';
4
+ import React from 'react';
5
5
 
6
6
  import { useAuth, useDeleteAccount } from '@djangocfg/api/auth';
7
7
  import { useAppT } from '@djangocfg/i18n';
8
- import { Alert, AlertDescription, Button, Input } from '@djangocfg/ui-core/components';
9
8
 
10
- import { useProfileContext } from '../context';
11
9
  import { ActionButton } from './ActionButton';
12
10
 
13
- // ─── Entry point: single action row on main screen ───────────────────────────
14
-
15
11
  export const DeleteAccountSection: React.FC = () => {
16
- const { setStep } = useProfileContext();
17
- const t = useAppT();
18
-
19
- return (
20
- <ActionButton
21
- icon={<Trash2 className="w-4 h-4 text-destructive" />}
22
- label={<span className="text-destructive">{t('layouts.profilePage.deleteAccount')}</span>}
23
- onClick={() => setStep('delete-account')}
24
- />
25
- );
26
- };
27
-
28
- // ─── Full delete screen ───────────────────────────────────────────────────────
29
-
30
- export const DeleteAccountScreen: React.FC = () => {
31
- const { back } = useProfileContext();
32
12
  const { logout } = useAuth();
33
- const [confirmationInput, setConfirmationInput] = useState('');
13
+ const { deleteAccount } = useDeleteAccount();
34
14
  const t = useAppT();
35
15
 
36
- const { isLoading, error, deleteAccount, clearError } = useDeleteAccount();
37
-
38
16
  const confirmationWord = t('layouts.profilePage.confirmationWord');
39
- const isValid = confirmationInput.toUpperCase() === confirmationWord.toUpperCase();
40
17
 
41
- const labels = useMemo(() => ({
42
- back: t('layouts.navigation.back'),
43
- title: t('layouts.profilePage.deleteAccountTitle'),
44
- desc: t('layouts.profilePage.deleteAccountDesc'),
45
- typeToConfirm: t('layouts.profilePage.typeToConfirm').replace('{word}', confirmationWord),
46
- deleting: t('layouts.profilePage.deleting'),
47
- deleteAccount: t('layouts.profilePage.deleteAccount'),
48
- cancel: t('layouts.profilePage.cancel'),
49
- }), [t, confirmationWord]);
18
+ const handleClick = async () => {
19
+ const value = await window.dialog.prompt({
20
+ title: t('layouts.profilePage.deleteAccountTitle'),
21
+ message: t('layouts.profilePage.deleteAccountDesc'),
22
+ placeholder: confirmationWord,
23
+ confirmText: t('layouts.profilePage.deleteAccount'),
24
+ cancelText: t('layouts.profilePage.cancel'),
25
+ variant: 'destructive',
26
+ });
27
+
28
+ if (value?.toUpperCase() !== confirmationWord.toUpperCase()) return;
50
29
 
51
- const handleDelete = async () => {
52
- clearError();
53
30
  const result = await deleteAccount();
54
31
  if (result.success) logout();
55
32
  };
56
33
 
57
- const handleBack = () => {
58
- clearError();
59
- setConfirmationInput('');
60
- back();
61
- };
62
-
63
34
  return (
64
- <div className="container mx-auto px-4 py-12 max-w-md">
65
- {/* Back */}
66
- <button
67
- type="button"
68
- onClick={handleBack}
69
- className="flex items-center gap-1 text-sm text-muted-foreground mb-8 hover:text-foreground transition-colors"
70
- >
71
- <ChevronLeft className="w-4 h-4" />
72
- {labels.back}
73
- </button>
74
-
75
- {/* Header */}
76
- <div className="flex items-center gap-3 mb-2">
77
- <div className="w-10 h-10 rounded-full bg-destructive/10 flex items-center justify-center">
78
- <AlertTriangle className="w-5 h-5 text-destructive" />
79
- </div>
80
- <h1 className="text-xl font-semibold">{labels.title}</h1>
81
- </div>
82
- <p className="text-sm text-muted-foreground mb-8">{labels.desc}</p>
83
-
84
- {/* Confirmation */}
85
- <div className="space-y-3">
86
- {error && (
87
- <Alert variant="destructive">
88
- <AlertDescription>{error}</AlertDescription>
89
- </Alert>
90
- )}
91
-
92
- <p className="text-sm text-muted-foreground">{labels.typeToConfirm}</p>
93
-
94
- <Input
95
- value={confirmationInput}
96
- onChange={(e) => setConfirmationInput(e.target.value)}
97
- placeholder={confirmationWord}
98
- disabled={isLoading}
99
- autoFocus
100
- autoComplete="off"
101
- className="font-mono"
102
- />
103
-
104
- <Button
105
- variant="destructive"
106
- className="w-full"
107
- onClick={handleDelete}
108
- disabled={isLoading || !isValid}
109
- >
110
- {isLoading ? (
111
- <><Loader2 className="mr-2 h-4 w-4 animate-spin" />{labels.deleting}</>
112
- ) : (
113
- labels.deleteAccount
114
- )}
115
- </Button>
116
-
117
- <Button
118
- variant="ghost"
119
- className="w-full"
120
- onClick={handleBack}
121
- disabled={isLoading}
122
- >
123
- {labels.cancel}
124
- </Button>
125
- </div>
126
- </div>
35
+ <ActionButton
36
+ icon={<Trash2 className="w-4 h-4 text-destructive" />}
37
+ label={<span className="text-destructive">{t('layouts.profilePage.deleteAccount')}</span>}
38
+ onClick={handleClick}
39
+ />
127
40
  );
128
41
  };
42
+
43
+ // Keep export so nothing breaks — no longer used but exported for backwards compat
44
+ export const DeleteAccountScreen: React.FC = () => null;
@@ -1,11 +1,22 @@
1
1
  'use client';
2
2
 
3
- import React, { useEffect, useMemo, useState } from 'react';
3
+ import React, { useEffect, useState } from 'react';
4
+ import { parsePhoneNumberFromString } from 'libphonenumber-js';
4
5
 
5
- import { useAppT } from '@djangocfg/i18n';
6
6
  import { Button, Input, PhoneInput } from '@djangocfg/ui-core/components';
7
7
  import { cn } from '@djangocfg/ui-core/lib';
8
8
 
9
+ import { useProfileContext } from '../context';
10
+
11
+ function formatPhone(raw: string): string {
12
+ if (!raw) return '';
13
+ try {
14
+ return parsePhoneNumberFromString(raw)?.formatInternational() ?? raw;
15
+ } catch {
16
+ return raw;
17
+ }
18
+ }
19
+
9
20
  interface EditableFieldProps {
10
21
  label: string;
11
22
  value: string;
@@ -23,17 +34,11 @@ export const EditableField = ({
23
34
  disabled,
24
35
  type = 'text',
25
36
  }: EditableFieldProps) => {
26
- const t = useAppT();
37
+ const { labels } = useProfileContext();
27
38
  const [isEditing, setIsEditing] = useState(false);
28
39
  const [editValue, setEditValue] = useState(value);
29
40
  const [isSaving, setIsSaving] = useState(false);
30
41
 
31
- const labels = useMemo(() => ({
32
- save: t('layouts.profilePage.save'),
33
- saving: t('layouts.profilePage.saving'),
34
- cancel: t('layouts.profilePage.cancel'),
35
- }), [t]);
36
-
37
42
  useEffect(() => {
38
43
  setEditValue(value);
39
44
  }, [value]);
@@ -112,7 +117,7 @@ export const EditableField = ({
112
117
  >
113
118
  <div className="text-[13px] text-muted-foreground mb-0.5">{label}</div>
114
119
  <div className={cn('text-[15px]', value ? 'text-foreground' : 'text-muted-foreground/60')}>
115
- {value || placeholder}
120
+ {value ? (type === 'phone' ? formatPhone(value) : value) : placeholder}
116
121
  </div>
117
122
  </button>
118
123
  );
@@ -11,7 +11,7 @@ interface SectionProps {
11
11
  }
12
12
 
13
13
  export const Section = ({ title, children, className }: SectionProps) => (
14
- <div className={cn('mb-10', className)}>
14
+ <div className={cn('mb-4 md:mb-6', className)}>
15
15
  {title && (
16
16
  <h2 className="text-[11px] font-medium text-muted-foreground uppercase tracking-wider mb-2 px-1">
17
17
  {title}