ar-saas 0.3.2 → 0.4.0
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/dist/generator.js +2 -6
- package/package.json +1 -1
- package/templates/backend/.env.example +1 -1
- package/templates/backend/package.json +5 -2
- package/templates/backend/src/app.module.ts +68 -40
- package/templates/backend/src/common/interceptors/workspace-tenant.interceptor.ts +27 -45
- package/templates/backend/src/main.ts +50 -51
- package/templates/backend/src/modules/auth/auth.controller.ts +162 -158
- package/templates/backend/src/modules/auth/auth.service.ts +236 -257
- package/templates/backend/src/modules/auth/strategies/jwt.strategy.ts +45 -43
- package/templates/backend/src/modules/users/users.controller.ts +28 -0
- package/templates/backend/src/modules/users/users.module.ts +16 -14
- package/templates/backend/src/modules/users/users.repository.ts +57 -51
- package/templates/backend/src/modules/users/users.service.ts +130 -104
- package/templates/backend/src/modules/workspaces/workspaces.repository.ts +38 -34
- package/templates/backend/src/modules/workspaces/workspaces.service.ts +51 -42
- package/templates/frontend/package.json +2 -5
- package/templates/frontend/pnpm-workspace.yaml +2 -2
- package/templates/frontend/src/app/(auth)/layout.tsx +29 -28
- package/templates/frontend/src/app/(dashboard)/billing/page.tsx +111 -111
- package/templates/frontend/src/app/(dashboard)/profile/page.tsx +241 -226
- package/templates/frontend/src/app/(dashboard)/settings/page.tsx +155 -156
- package/templates/frontend/src/app/(dashboard)/team/page.tsx +179 -178
- package/templates/frontend/src/app/layout.tsx +29 -26
- package/templates/frontend/src/app/page.tsx +1 -1
- package/templates/frontend/src/app/setup/page.tsx +1 -1
- package/templates/frontend/src/components/dashboard/header.tsx +5 -3
- package/templates/frontend/src/config/site.ts +1 -1
|
@@ -1,156 +1,155 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
5
|
-
import { Switch } from '@/components/ui/switch'
|
|
6
|
-
import { Separator } from '@/components/ui/separator'
|
|
7
|
-
import { Button } from '@/components/ui/button'
|
|
8
|
-
import { Label } from '@/components/ui/label'
|
|
9
|
-
import { Badge } from '@/components/ui/badge'
|
|
10
|
-
|
|
11
|
-
interface NotificationSettings {
|
|
12
|
-
emailMarketing: boolean
|
|
13
|
-
emailProduct: boolean
|
|
14
|
-
emailSecurity: boolean
|
|
15
|
-
pushAll: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface WorkspaceSettings {
|
|
19
|
-
publicProfile: boolean
|
|
20
|
-
allowInvites: boolean
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default function SettingsPage() {
|
|
24
|
-
const [notifications, setNotifications] = useState<NotificationSettings>({
|
|
25
|
-
emailMarketing: false,
|
|
26
|
-
emailProduct: true,
|
|
27
|
-
emailSecurity: true,
|
|
28
|
-
pushAll: false,
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
const [workspace, setWorkspace] = useState<WorkspaceSettings>({
|
|
32
|
-
publicProfile: false,
|
|
33
|
-
allowInvites: true,
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
<p className="text-
|
|
146
|
-
|
|
147
|
-
</
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
5
|
+
import { Switch } from '@/components/ui/switch'
|
|
6
|
+
import { Separator } from '@/components/ui/separator'
|
|
7
|
+
import { Button } from '@/components/ui/button'
|
|
8
|
+
import { Label } from '@/components/ui/label'
|
|
9
|
+
import { Badge } from '@/components/ui/badge'
|
|
10
|
+
|
|
11
|
+
interface NotificationSettings {
|
|
12
|
+
emailMarketing: boolean
|
|
13
|
+
emailProduct: boolean
|
|
14
|
+
emailSecurity: boolean
|
|
15
|
+
pushAll: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface WorkspaceSettings {
|
|
19
|
+
publicProfile: boolean
|
|
20
|
+
allowInvites: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default function SettingsPage() {
|
|
24
|
+
const [notifications, setNotifications] = useState<NotificationSettings>({
|
|
25
|
+
emailMarketing: false,
|
|
26
|
+
emailProduct: true,
|
|
27
|
+
emailSecurity: true,
|
|
28
|
+
pushAll: false,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const [workspace, setWorkspace] = useState<WorkspaceSettings>({
|
|
32
|
+
publicProfile: false,
|
|
33
|
+
allowInvites: true,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
function toggleNotification(key: keyof NotificationSettings) {
|
|
37
|
+
setNotifications((prev) => ({ ...prev, [key]: !prev[key] }))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function toggleWorkspace(key: keyof WorkspaceSettings) {
|
|
41
|
+
setWorkspace((prev) => ({ ...prev, [key]: !prev[key] }))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="max-w-2xl space-y-6">
|
|
46
|
+
<div className="rounded-lg border border-amber-200 bg-amber-50 p-3">
|
|
47
|
+
<p className="text-xs text-amber-800 font-medium">Próximamente</p>
|
|
48
|
+
<p className="text-xs text-amber-700 mt-0.5">La configuración de notificaciones y workspace estará disponible en la próxima actualización.</p>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
{/* Notificaciones */}
|
|
52
|
+
<Card>
|
|
53
|
+
<CardHeader>
|
|
54
|
+
<CardTitle>Notificaciones por email</CardTitle>
|
|
55
|
+
<CardDescription>Elegí qué correos querés recibir de nuestra parte.</CardDescription>
|
|
56
|
+
</CardHeader>
|
|
57
|
+
<CardContent className="space-y-4">
|
|
58
|
+
{[
|
|
59
|
+
{
|
|
60
|
+
key: 'emailSecurity' as const,
|
|
61
|
+
label: 'Seguridad',
|
|
62
|
+
description: 'Alertas de inicio de sesión y cambios de contraseña.',
|
|
63
|
+
badge: 'Recomendado',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: 'emailProduct' as const,
|
|
67
|
+
label: 'Actualizaciones del producto',
|
|
68
|
+
description: 'Nuevas funcionalidades, mejoras y fixes importantes.',
|
|
69
|
+
badge: null,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: 'emailMarketing' as const,
|
|
73
|
+
label: 'Marketing y promociones',
|
|
74
|
+
description: 'Ofertas, descuentos y contenido educativo.',
|
|
75
|
+
badge: null,
|
|
76
|
+
},
|
|
77
|
+
].map(({ key, label, description, badge }) => (
|
|
78
|
+
<div key={key} className="flex items-start justify-between gap-4">
|
|
79
|
+
<div className="space-y-0.5">
|
|
80
|
+
<div className="flex items-center gap-2">
|
|
81
|
+
<Label className="text-sm font-medium">{label}</Label>
|
|
82
|
+
{badge && <Badge variant="secondary" className="text-xs">{badge}</Badge>}
|
|
83
|
+
</div>
|
|
84
|
+
<p className="text-xs text-muted-foreground">{description}</p>
|
|
85
|
+
</div>
|
|
86
|
+
<Switch
|
|
87
|
+
checked={notifications[key]}
|
|
88
|
+
onCheckedChange={() => toggleNotification(key)}
|
|
89
|
+
disabled
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
))}
|
|
93
|
+
</CardContent>
|
|
94
|
+
</Card>
|
|
95
|
+
|
|
96
|
+
{/* Workspace */}
|
|
97
|
+
<Card>
|
|
98
|
+
<CardHeader>
|
|
99
|
+
<CardTitle>Workspace</CardTitle>
|
|
100
|
+
<CardDescription>Configuración de tu espacio de trabajo.</CardDescription>
|
|
101
|
+
</CardHeader>
|
|
102
|
+
<CardContent className="space-y-4">
|
|
103
|
+
<div className="flex items-start justify-between gap-4">
|
|
104
|
+
<div className="space-y-0.5">
|
|
105
|
+
<Label className="text-sm font-medium">Perfil público</Label>
|
|
106
|
+
<p className="text-xs text-muted-foreground">
|
|
107
|
+
Permite que otros usuarios encuentren tu perfil.
|
|
108
|
+
</p>
|
|
109
|
+
</div>
|
|
110
|
+
<Switch
|
|
111
|
+
checked={workspace.publicProfile}
|
|
112
|
+
onCheckedChange={() => toggleWorkspace('publicProfile')}
|
|
113
|
+
disabled
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<Separator />
|
|
118
|
+
|
|
119
|
+
<div className="flex items-start justify-between gap-4">
|
|
120
|
+
<div className="space-y-0.5">
|
|
121
|
+
<Label className="text-sm font-medium">Invitaciones de equipo</Label>
|
|
122
|
+
<p className="text-xs text-muted-foreground">
|
|
123
|
+
Permite que otros te inviten a sus workspaces.
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
<Switch
|
|
127
|
+
checked={workspace.allowInvites}
|
|
128
|
+
onCheckedChange={() => toggleWorkspace('allowInvites')}
|
|
129
|
+
disabled
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
</CardContent>
|
|
133
|
+
</Card>
|
|
134
|
+
|
|
135
|
+
{/* Danger zone */}
|
|
136
|
+
<Card className="border-destructive/40">
|
|
137
|
+
<CardHeader>
|
|
138
|
+
<CardTitle className="text-destructive">Zona peligrosa</CardTitle>
|
|
139
|
+
<CardDescription>Acciones irreversibles sobre tu cuenta.</CardDescription>
|
|
140
|
+
</CardHeader>
|
|
141
|
+
<CardContent className="space-y-3">
|
|
142
|
+
<div className="flex items-center justify-between">
|
|
143
|
+
<div>
|
|
144
|
+
<p className="text-sm font-medium">Exportar mis datos</p>
|
|
145
|
+
<p className="text-xs text-muted-foreground">Descargá toda tu información en formato JSON.</p>
|
|
146
|
+
</div>
|
|
147
|
+
<Button variant="outline" size="sm" disabled>Exportar</Button>
|
|
148
|
+
</div>
|
|
149
|
+
</CardContent>
|
|
150
|
+
</Card>
|
|
151
|
+
|
|
152
|
+
<Button disabled>Guardar ajustes</Button>
|
|
153
|
+
</div>
|
|
154
|
+
)
|
|
155
|
+
}
|