@hed-hog/lms 0.0.329 → 0.0.330
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/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +18 -8
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +7 -5
- package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +5 -9
- package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +5 -9
- package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +15 -14
- package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +66 -29
- package/hedhog/frontend/app/certificates/models/TemplateEditorPage.tsx.ejs +4 -2
- package/hedhog/frontend/app/certificates/models/TopBar.tsx.ejs +44 -34
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +10 -10
- package/hedhog/frontend/app/classes/page.tsx.ejs +23 -15
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +5 -3
- package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +5 -3
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +9 -7
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-skeleton.tsx.ejs +3 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +4 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +24 -23
- package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +21 -19
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +7 -5
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +18 -16
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +13 -11
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +5 -3
- package/hedhog/frontend/app/courses/[id]/structure/_components/use-course-structure-shortcuts.ts.ejs +14 -9
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +42 -25
- package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +3 -1
- package/hedhog/frontend/app/enterprise/_components/enterprise-administrators-tab.tsx.ejs +10 -8
- package/hedhog/frontend/app/enterprise/_components/enterprise-classes-tab.tsx.ejs +22 -20
- package/hedhog/frontend/app/enterprise/_components/enterprise-course-create-sheet.tsx.ejs +3 -3
- package/hedhog/frontend/app/enterprise/_components/enterprise-courses-tab.tsx.ejs +21 -19
- package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +34 -36
- package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +3 -1
- package/hedhog/frontend/app/enterprise/_components/enterprise-students-tab.tsx.ejs +7 -5
- package/hedhog/frontend/app/enterprise/page.tsx.ejs +106 -54
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +79 -59
- package/hedhog/frontend/app/instructors/page.tsx.ejs +4 -2
- package/hedhog/frontend/messages/en.json +619 -13
- package/hedhog/frontend/messages/pt.json +619 -13
- package/package.json +7 -7
|
@@ -30,6 +30,7 @@ import { Switch } from '@/components/ui/switch';
|
|
|
30
30
|
import { Textarea } from '@/components/ui/textarea';
|
|
31
31
|
import { useApp } from '@hed-hog/next-app-provider';
|
|
32
32
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
33
|
+
import { useTranslations } from 'next-intl';
|
|
33
34
|
import { useEffect } from 'react';
|
|
34
35
|
import { useForm } from 'react-hook-form';
|
|
35
36
|
import { toast } from 'sonner';
|
|
@@ -86,6 +87,7 @@ export function EnterpriseSheet({
|
|
|
86
87
|
}: EnterpriseSheetProps) {
|
|
87
88
|
const isEditing = Boolean(editingAccount);
|
|
88
89
|
const { request } = useApp();
|
|
90
|
+
const t = useTranslations('lms.EnterprisePage.sheet');
|
|
89
91
|
|
|
90
92
|
const form = useForm<EnterpriseFormValues>({
|
|
91
93
|
resolver: zodResolver(enterpriseSchema),
|
|
@@ -163,14 +165,12 @@ export function EnterpriseSheet({
|
|
|
163
165
|
|
|
164
166
|
onSave?.(values, isEditing);
|
|
165
167
|
toast.success(
|
|
166
|
-
isEditing
|
|
167
|
-
? 'Account updated successfully.'
|
|
168
|
-
: 'Account created successfully.'
|
|
168
|
+
isEditing ? t('messages.updateSuccess') : t('messages.createSuccess')
|
|
169
169
|
);
|
|
170
170
|
onOpenChange(false);
|
|
171
171
|
} catch {
|
|
172
172
|
toast.error(
|
|
173
|
-
isEditing ? '
|
|
173
|
+
isEditing ? t('messages.updateError') : t('messages.createError')
|
|
174
174
|
);
|
|
175
175
|
}
|
|
176
176
|
}
|
|
@@ -180,12 +180,10 @@ export function EnterpriseSheet({
|
|
|
180
180
|
<SheetContent className="w-full overflow-y-auto sm:max-w-lg">
|
|
181
181
|
<SheetHeader>
|
|
182
182
|
<SheetTitle>
|
|
183
|
-
{isEditing ? '
|
|
183
|
+
{isEditing ? t('editTitle') : t('createTitle')}
|
|
184
184
|
</SheetTitle>
|
|
185
185
|
<SheetDescription>
|
|
186
|
-
{isEditing
|
|
187
|
-
? 'Update the corporate account details below.'
|
|
188
|
-
: 'Register a new corporate account in the LMS platform.'}
|
|
186
|
+
{isEditing ? t('editDescription') : t('createDescription')}
|
|
189
187
|
</SheetDescription>
|
|
190
188
|
</SheetHeader>
|
|
191
189
|
|
|
@@ -200,9 +198,9 @@ export function EnterpriseSheet({
|
|
|
200
198
|
name="name"
|
|
201
199
|
render={({ field }) => (
|
|
202
200
|
<FormItem>
|
|
203
|
-
<FormLabel>
|
|
201
|
+
<FormLabel>{t('fields.name')}</FormLabel>
|
|
204
202
|
<FormControl>
|
|
205
|
-
<Input placeholder=
|
|
203
|
+
<Input placeholder={t('fields.namePlaceholder')} {...field} />
|
|
206
204
|
</FormControl>
|
|
207
205
|
<FormMessage />
|
|
208
206
|
</FormItem>
|
|
@@ -215,13 +213,12 @@ export function EnterpriseSheet({
|
|
|
215
213
|
name="slug"
|
|
216
214
|
render={({ field }) => (
|
|
217
215
|
<FormItem>
|
|
218
|
-
<FormLabel>
|
|
216
|
+
<FormLabel>{t('fields.slug')}</FormLabel>
|
|
219
217
|
<FormControl>
|
|
220
|
-
<Input placeholder=
|
|
218
|
+
<Input placeholder={t('fields.slugPlaceholder')} {...field} />
|
|
221
219
|
</FormControl>
|
|
222
220
|
<FormDescription>
|
|
223
|
-
|
|
224
|
-
from the name when creating.
|
|
221
|
+
{t('fields.slugDescription')}
|
|
225
222
|
</FormDescription>
|
|
226
223
|
<FormMessage />
|
|
227
224
|
</FormItem>
|
|
@@ -234,17 +231,17 @@ export function EnterpriseSheet({
|
|
|
234
231
|
name="status"
|
|
235
232
|
render={({ field }) => (
|
|
236
233
|
<FormItem>
|
|
237
|
-
<FormLabel>
|
|
234
|
+
<FormLabel>{t('fields.status')}</FormLabel>
|
|
238
235
|
<FormControl>
|
|
239
236
|
<Select value={field.value} onValueChange={field.onChange}>
|
|
240
237
|
<SelectTrigger className="w-full">
|
|
241
238
|
<SelectValue />
|
|
242
239
|
</SelectTrigger>
|
|
243
240
|
<SelectContent>
|
|
244
|
-
<SelectItem value="active">
|
|
245
|
-
<SelectItem value="trial">
|
|
246
|
-
<SelectItem value="inactive">
|
|
247
|
-
<SelectItem value="suspended">
|
|
241
|
+
<SelectItem value="active">{t('status.active')}</SelectItem>
|
|
242
|
+
<SelectItem value="trial">{t('status.trial')}</SelectItem>
|
|
243
|
+
<SelectItem value="inactive">{t('status.inactive')}</SelectItem>
|
|
244
|
+
<SelectItem value="suspended">{t('status.suspended')}</SelectItem>
|
|
248
245
|
</SelectContent>
|
|
249
246
|
</Select>
|
|
250
247
|
</FormControl>
|
|
@@ -262,11 +259,11 @@ export function EnterpriseSheet({
|
|
|
262
259
|
shouldValidate: true,
|
|
263
260
|
})
|
|
264
261
|
}
|
|
265
|
-
label=
|
|
266
|
-
placeholder=
|
|
267
|
-
searchPlaceholder=
|
|
268
|
-
emptyLabel=
|
|
269
|
-
entityLabel=
|
|
262
|
+
label={t('fields.company')}
|
|
263
|
+
placeholder={t('fields.companyPlaceholder')}
|
|
264
|
+
searchPlaceholder={t('fields.companySearchPlaceholder')}
|
|
265
|
+
emptyLabel={t('fields.companyEmpty')}
|
|
266
|
+
entityLabel={t('fields.companyEntity')}
|
|
270
267
|
clearable
|
|
271
268
|
valueType="number"
|
|
272
269
|
loadOptions={async ({ page, pageSize, search }) => {
|
|
@@ -290,8 +287,8 @@ export function EnterpriseSheet({
|
|
|
290
287
|
createFields={[
|
|
291
288
|
{
|
|
292
289
|
name: 'name',
|
|
293
|
-
label: '
|
|
294
|
-
placeholder: '
|
|
290
|
+
label: t('fields.companyCreateName'),
|
|
291
|
+
placeholder: t('fields.companyCreateNamePlaceholder'),
|
|
295
292
|
required: true,
|
|
296
293
|
},
|
|
297
294
|
]}
|
|
@@ -317,11 +314,10 @@ export function EnterpriseSheet({
|
|
|
317
314
|
<FormItem className="flex items-center justify-between rounded-lg border px-4 py-3">
|
|
318
315
|
<div className="space-y-0.5">
|
|
319
316
|
<FormLabel className="text-sm font-medium">
|
|
320
|
-
|
|
317
|
+
{t('fields.portalEnabled')}
|
|
321
318
|
</FormLabel>
|
|
322
319
|
<FormDescription className="text-xs">
|
|
323
|
-
|
|
324
|
-
portal.
|
|
320
|
+
{t('fields.portalEnabledDescription')}
|
|
325
321
|
</FormDescription>
|
|
326
322
|
</div>
|
|
327
323
|
<FormControl>
|
|
@@ -340,12 +336,12 @@ export function EnterpriseSheet({
|
|
|
340
336
|
name="licenseLimit"
|
|
341
337
|
render={({ field }) => (
|
|
342
338
|
<FormItem>
|
|
343
|
-
<FormLabel>
|
|
339
|
+
<FormLabel>{t('fields.licenseLimit')}</FormLabel>
|
|
344
340
|
<FormControl>
|
|
345
341
|
<Input
|
|
346
342
|
type="number"
|
|
347
343
|
min={1}
|
|
348
|
-
placeholder=
|
|
344
|
+
placeholder={t('fields.licenseLimitPlaceholder')}
|
|
349
345
|
value={field.value ?? ''}
|
|
350
346
|
onChange={(e) =>
|
|
351
347
|
field.onChange(
|
|
@@ -355,7 +351,7 @@ export function EnterpriseSheet({
|
|
|
355
351
|
/>
|
|
356
352
|
</FormControl>
|
|
357
353
|
<FormDescription>
|
|
358
|
-
|
|
354
|
+
{t('fields.licenseLimitDescription')}
|
|
359
355
|
</FormDescription>
|
|
360
356
|
<FormMessage />
|
|
361
357
|
</FormItem>
|
|
@@ -368,10 +364,10 @@ export function EnterpriseSheet({
|
|
|
368
364
|
name="notes"
|
|
369
365
|
render={({ field }) => (
|
|
370
366
|
<FormItem>
|
|
371
|
-
<FormLabel>
|
|
367
|
+
<FormLabel>{t('fields.notes')}</FormLabel>
|
|
372
368
|
<FormControl>
|
|
373
369
|
<Textarea
|
|
374
|
-
placeholder=
|
|
370
|
+
placeholder={t('fields.notesPlaceholder')}
|
|
375
371
|
rows={3}
|
|
376
372
|
{...field}
|
|
377
373
|
value={field.value ?? ''}
|
|
@@ -384,9 +380,11 @@ export function EnterpriseSheet({
|
|
|
384
380
|
|
|
385
381
|
<FormActions
|
|
386
382
|
sheet
|
|
387
|
-
cancelLabel=
|
|
383
|
+
cancelLabel={t('actions.cancel')}
|
|
388
384
|
onCancel={() => onOpenChange(false)}
|
|
389
|
-
submitLabel={
|
|
385
|
+
submitLabel={
|
|
386
|
+
isEditing ? t('actions.saveChanges') : t('actions.create')
|
|
387
|
+
}
|
|
390
388
|
submitType="submit"
|
|
391
389
|
/>
|
|
392
390
|
</form>
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { useApp } from '@hed-hog/next-app-provider';
|
|
22
22
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
23
23
|
import { Loader2 } from 'lucide-react';
|
|
24
|
+
import { useTranslations } from 'next-intl';
|
|
24
25
|
import { useEffect, useState } from 'react';
|
|
25
26
|
import { useForm } from 'react-hook-form';
|
|
26
27
|
import { toast } from 'sonner';
|
|
@@ -57,6 +58,7 @@ export function EnterpriseStudentCreateSheet({
|
|
|
57
58
|
onOpenChange,
|
|
58
59
|
onCreated,
|
|
59
60
|
}: EnterpriseStudentCreateSheetProps) {
|
|
61
|
+
const t = useTranslations('lms.EnterprisePage');
|
|
60
62
|
const { request } = useApp();
|
|
61
63
|
const [saving, setSaving] = useState(false);
|
|
62
64
|
|
|
@@ -90,7 +92,7 @@ export function EnterpriseStudentCreateSheet({
|
|
|
90
92
|
onCreated?.(personId);
|
|
91
93
|
handleOpenChange(false);
|
|
92
94
|
} catch {
|
|
93
|
-
toast.error('
|
|
95
|
+
toast.error(t('sheet.studentCreated'));
|
|
94
96
|
} finally {
|
|
95
97
|
setSaving(false);
|
|
96
98
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { formatDate } from '@/lib/format-date';
|
|
16
16
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
17
17
|
import { Trash2 } from 'lucide-react';
|
|
18
|
+
import { useTranslations } from 'next-intl';
|
|
18
19
|
import { useCallback, useState } from 'react';
|
|
19
20
|
import { toast } from 'sonner';
|
|
20
21
|
import {
|
|
@@ -39,6 +40,7 @@ export function StudentsTab({
|
|
|
39
40
|
enterpriseId: number;
|
|
40
41
|
onMutate?: () => void;
|
|
41
42
|
}) {
|
|
43
|
+
const t = useTranslations('lms.EnterprisePage');
|
|
42
44
|
const { request, getSettingValue, currentLocaleCode } = useApp();
|
|
43
45
|
const [search, setSearch] = useState('');
|
|
44
46
|
const [page, setPage] = useState(1);
|
|
@@ -93,7 +95,7 @@ export function StudentsTab({
|
|
|
93
95
|
refetch();
|
|
94
96
|
onMutate?.();
|
|
95
97
|
} catch {
|
|
96
|
-
toast.error('
|
|
98
|
+
toast.error(t('sheet.studentAddError'));
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
|
|
@@ -107,9 +109,9 @@ export function StudentsTab({
|
|
|
107
109
|
onMutate?.();
|
|
108
110
|
});
|
|
109
111
|
toast.promise(promise, {
|
|
110
|
-
loading: '
|
|
111
|
-
success: '
|
|
112
|
-
error: '
|
|
112
|
+
loading: t('sheet.studentRemoving'),
|
|
113
|
+
success: t('sheet.studentRemoved'),
|
|
114
|
+
error: t('sheet.studentRemoveError'),
|
|
113
115
|
});
|
|
114
116
|
try {
|
|
115
117
|
await promise;
|
|
@@ -255,7 +257,7 @@ export function StudentsTab({
|
|
|
255
257
|
data: { person_id: personId, status: 'active' },
|
|
256
258
|
});
|
|
257
259
|
} catch {
|
|
258
|
-
toast.error('
|
|
260
|
+
toast.error(t('sheet.studentLinkError'));
|
|
259
261
|
}
|
|
260
262
|
setCreateSheetOpen(false);
|
|
261
263
|
refetch();
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
SquareArrowOutUpRight,
|
|
45
45
|
Users,
|
|
46
46
|
} from 'lucide-react';
|
|
47
|
+
import { useTranslations } from 'next-intl';
|
|
47
48
|
import { useMemo, useState } from 'react';
|
|
48
49
|
import { EnterpriseDetailSheet } from './_components/enterprise-detail-sheet';
|
|
49
50
|
import { EnterpriseSheet } from './_components/enterprise-sheet';
|
|
@@ -69,16 +70,10 @@ const STATUS_VARIANT: Record<
|
|
|
69
70
|
suspended: 'destructive',
|
|
70
71
|
};
|
|
71
72
|
|
|
72
|
-
const STATUS_LABEL: Record<EnterpriseStatus, string> = {
|
|
73
|
-
active: 'Active',
|
|
74
|
-
trial: 'Trial',
|
|
75
|
-
inactive: 'Inactive',
|
|
76
|
-
suspended: 'Suspended',
|
|
77
|
-
};
|
|
78
|
-
|
|
79
73
|
// ── Page ──────────────────────────────────────────────────────────────────────
|
|
80
74
|
|
|
81
75
|
export default function EnterprisePage() {
|
|
76
|
+
const t = useTranslations('lms.EnterprisePage');
|
|
82
77
|
const [search, setSearch] = useState('');
|
|
83
78
|
const [statusFilter, setStatusFilter] = useState('all');
|
|
84
79
|
const [crmFilter, setCrmFilter] = useState('all');
|
|
@@ -205,42 +200,48 @@ export default function EnterprisePage() {
|
|
|
205
200
|
return [
|
|
206
201
|
{
|
|
207
202
|
key: 'total',
|
|
208
|
-
title: '
|
|
203
|
+
title: t('kpis.total.label'),
|
|
209
204
|
value: total,
|
|
210
|
-
description: '
|
|
205
|
+
description: t('kpis.total.description'),
|
|
211
206
|
icon: Building2,
|
|
212
207
|
accentClassName: 'from-slate-500/20 via-slate-400/10 to-transparent',
|
|
213
208
|
iconContainerClassName: 'bg-slate-100 text-slate-700',
|
|
214
209
|
},
|
|
215
210
|
{
|
|
216
211
|
key: 'active',
|
|
217
|
-
title: '
|
|
212
|
+
title: t('kpis.active.label'),
|
|
218
213
|
value: active,
|
|
219
|
-
description: '
|
|
214
|
+
description: t('kpis.active.description'),
|
|
220
215
|
icon: Users,
|
|
221
216
|
accentClassName: 'from-green-500/20 via-emerald-500/10 to-transparent',
|
|
222
217
|
iconContainerClassName: 'bg-green-50 text-green-600',
|
|
223
218
|
},
|
|
224
219
|
{
|
|
225
220
|
key: 'trial',
|
|
226
|
-
title: 'Trial',
|
|
221
|
+
title: t.has('kpis.trial.label') ? t('kpis.trial.label') : 'Trial',
|
|
227
222
|
value: trial,
|
|
228
|
-
description: '
|
|
223
|
+
description: t.has('kpis.trial.description')
|
|
224
|
+
? t('kpis.trial.description')
|
|
225
|
+
: 'In trial period',
|
|
229
226
|
icon: CalendarDays,
|
|
230
227
|
accentClassName: 'from-amber-500/20 via-orange-500/10 to-transparent',
|
|
231
228
|
iconContainerClassName: 'bg-amber-50 text-amber-600',
|
|
232
229
|
},
|
|
233
230
|
{
|
|
234
231
|
key: 'portal',
|
|
235
|
-
title: '
|
|
232
|
+
title: t.has('kpis.portal.label')
|
|
233
|
+
? t('kpis.portal.label')
|
|
234
|
+
: 'Portal Enabled',
|
|
236
235
|
value: withPortal,
|
|
237
|
-
description: '
|
|
236
|
+
description: t.has('kpis.portal.description')
|
|
237
|
+
? t('kpis.portal.description')
|
|
238
|
+
: 'Self-service portal access',
|
|
238
239
|
icon: Globe,
|
|
239
240
|
accentClassName: 'from-blue-500/20 via-cyan-500/10 to-transparent',
|
|
240
241
|
iconContainerClassName: 'bg-blue-50 text-blue-600',
|
|
241
242
|
},
|
|
242
243
|
];
|
|
243
|
-
}, [stats]);
|
|
244
|
+
}, [stats, t]);
|
|
244
245
|
|
|
245
246
|
const accounts = enterpriseList?.data ?? [];
|
|
246
247
|
const totalItems = enterpriseList?.total ?? 0;
|
|
@@ -271,11 +272,19 @@ export default function EnterprisePage() {
|
|
|
271
272
|
value: statusFilter,
|
|
272
273
|
onChange: handleStatusFilter,
|
|
273
274
|
options: [
|
|
274
|
-
{ value: 'all', label: '
|
|
275
|
-
{ value: 'active', label: '
|
|
276
|
-
{
|
|
277
|
-
|
|
278
|
-
|
|
275
|
+
{ value: 'all', label: t('filters.allStatuses') },
|
|
276
|
+
{ value: 'active', label: t('status.active') },
|
|
277
|
+
{
|
|
278
|
+
value: 'trial',
|
|
279
|
+
label: t.has('status.trial') ? t('status.trial') : 'Trial',
|
|
280
|
+
},
|
|
281
|
+
{ value: 'inactive', label: t('status.inactive') },
|
|
282
|
+
{
|
|
283
|
+
value: 'suspended',
|
|
284
|
+
label: t.has('status.suspended')
|
|
285
|
+
? t('status.suspended')
|
|
286
|
+
: 'Suspended',
|
|
287
|
+
},
|
|
279
288
|
],
|
|
280
289
|
},
|
|
281
290
|
{
|
|
@@ -283,7 +292,15 @@ export default function EnterprisePage() {
|
|
|
283
292
|
type: 'select',
|
|
284
293
|
value: crmFilter,
|
|
285
294
|
onChange: handleCrmFilter,
|
|
286
|
-
options: [
|
|
295
|
+
options: [
|
|
296
|
+
{
|
|
297
|
+
value: 'all',
|
|
298
|
+
label: t.has('filters.allCrmAccounts')
|
|
299
|
+
? t('filters.allCrmAccounts')
|
|
300
|
+
: 'All CRM accounts',
|
|
301
|
+
},
|
|
302
|
+
...crmOptions,
|
|
303
|
+
],
|
|
287
304
|
// options populated from API
|
|
288
305
|
},
|
|
289
306
|
];
|
|
@@ -291,14 +308,16 @@ export default function EnterprisePage() {
|
|
|
291
308
|
return (
|
|
292
309
|
<Page>
|
|
293
310
|
<PageHeader
|
|
311
|
+
title={t('title')}
|
|
312
|
+
description={t('description')}
|
|
294
313
|
breadcrumbs={[
|
|
295
|
-
{ label: '
|
|
296
|
-
{ label: '
|
|
297
|
-
{ label: '
|
|
314
|
+
{ label: t('breadcrumbs.home'), href: '/' },
|
|
315
|
+
{ label: t('breadcrumbs.lms'), href: '/lms' },
|
|
316
|
+
{ label: t('breadcrumbs.enterprise') },
|
|
298
317
|
]}
|
|
299
318
|
actions={[
|
|
300
319
|
{
|
|
301
|
-
label: '
|
|
320
|
+
label: t('actions.new'),
|
|
302
321
|
onClick: handleOpenCreate,
|
|
303
322
|
icon: <Plus className="h-4 w-4" />,
|
|
304
323
|
variant: 'default',
|
|
@@ -314,13 +333,13 @@ export default function EnterprisePage() {
|
|
|
314
333
|
searchQuery={search}
|
|
315
334
|
onSearchChange={handleSearch}
|
|
316
335
|
onSearch={() => {}}
|
|
317
|
-
placeholder=
|
|
336
|
+
placeholder={t('filters.searchPlaceholder')}
|
|
318
337
|
controls={controls}
|
|
319
338
|
/>
|
|
320
339
|
</div>
|
|
321
340
|
<div className="flex items-center gap-3">
|
|
322
341
|
<span className="text-xs font-medium text-muted-foreground">
|
|
323
|
-
View
|
|
342
|
+
{t.has('view.label') ? t('view.label') : 'View'}
|
|
324
343
|
</span>
|
|
325
344
|
<ToggleGroup
|
|
326
345
|
type="single"
|
|
@@ -328,15 +347,23 @@ export default function EnterprisePage() {
|
|
|
328
347
|
onValueChange={handleViewModeChange}
|
|
329
348
|
variant="outline"
|
|
330
349
|
size="sm"
|
|
331
|
-
aria-label=
|
|
350
|
+
aria-label={
|
|
351
|
+
t.has('view.modeAriaLabel')
|
|
352
|
+
? t('view.modeAriaLabel')
|
|
353
|
+
: 'View mode'
|
|
354
|
+
}
|
|
332
355
|
>
|
|
333
356
|
<ToggleGroupItem value="table" className="gap-1.5 px-2.5">
|
|
334
357
|
<List className="h-4 w-4" />
|
|
335
|
-
<span className="hidden sm:inline">
|
|
358
|
+
<span className="hidden sm:inline">
|
|
359
|
+
{t.has('view.table') ? t('view.table') : 'Table'}
|
|
360
|
+
</span>
|
|
336
361
|
</ToggleGroupItem>
|
|
337
362
|
<ToggleGroupItem value="cards" className="gap-1.5 px-2.5">
|
|
338
363
|
<LayoutGrid className="h-4 w-4" />
|
|
339
|
-
<span className="hidden sm:inline">
|
|
364
|
+
<span className="hidden sm:inline">
|
|
365
|
+
{t.has('view.cards') ? t('view.cards') : 'Cards'}
|
|
366
|
+
</span>
|
|
340
367
|
</ToggleGroupItem>
|
|
341
368
|
</ToggleGroup>
|
|
342
369
|
</div>
|
|
@@ -345,9 +372,9 @@ export default function EnterprisePage() {
|
|
|
345
372
|
{accounts.length === 0 && !isLoading ? (
|
|
346
373
|
<EmptyState
|
|
347
374
|
icon={<Building2 className="h-10 w-10" />}
|
|
348
|
-
title=
|
|
349
|
-
description=
|
|
350
|
-
actionLabel=
|
|
375
|
+
title={t('empty.title')}
|
|
376
|
+
description={t('empty.description')}
|
|
377
|
+
actionLabel={t('actions.new')}
|
|
351
378
|
onAction={handleOpenCreate}
|
|
352
379
|
actionIcon={<Plus className="h-4 w-4" />}
|
|
353
380
|
/>
|
|
@@ -356,13 +383,25 @@ export default function EnterprisePage() {
|
|
|
356
383
|
<Table>
|
|
357
384
|
<TableHeader>
|
|
358
385
|
<TableRow>
|
|
359
|
-
<TableHead>
|
|
360
|
-
<TableHead>
|
|
361
|
-
<TableHead>
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
386
|
+
<TableHead>{t('table.name')}</TableHead>
|
|
387
|
+
<TableHead>{t('table.status')}</TableHead>
|
|
388
|
+
<TableHead>
|
|
389
|
+
{t.has('table.crmAccount')
|
|
390
|
+
? t('table.crmAccount')
|
|
391
|
+
: 'CRM Account'}
|
|
392
|
+
</TableHead>
|
|
393
|
+
<TableHead className="text-center">
|
|
394
|
+
{t.has('table.classes') ? t('table.classes') : 'Classes'}
|
|
395
|
+
</TableHead>
|
|
396
|
+
<TableHead className="text-center">
|
|
397
|
+
{t('table.activeCourses')}
|
|
398
|
+
</TableHead>
|
|
399
|
+
<TableHead className="text-center">
|
|
400
|
+
{t.has('table.users') ? t('table.users') : 'Users'}
|
|
401
|
+
</TableHead>
|
|
402
|
+
<TableHead>
|
|
403
|
+
{t.has('table.updated') ? t('table.updated') : 'Updated'}
|
|
404
|
+
</TableHead>
|
|
366
405
|
<TableHead className="w-10" />
|
|
367
406
|
</TableRow>
|
|
368
407
|
</TableHeader>
|
|
@@ -381,14 +420,20 @@ export default function EnterprisePage() {
|
|
|
381
420
|
<>
|
|
382
421
|
<span className="opacity-30">·</span>
|
|
383
422
|
<Globe className="h-3 w-3 text-primary/60" />
|
|
384
|
-
<span className="text-primary/70">
|
|
423
|
+
<span className="text-primary/70">
|
|
424
|
+
{t.has('labels.portal')
|
|
425
|
+
? t('labels.portal')
|
|
426
|
+
: 'Portal'}
|
|
427
|
+
</span>
|
|
385
428
|
</>
|
|
386
429
|
)}
|
|
387
430
|
</p>
|
|
388
431
|
</TableCell>
|
|
389
432
|
<TableCell>
|
|
390
433
|
<Badge variant={STATUS_VARIANT[account.status]}>
|
|
391
|
-
{
|
|
434
|
+
{t.has(`status.${account.status}`)
|
|
435
|
+
? t(`status.${account.status}`)
|
|
436
|
+
: account.status}
|
|
392
437
|
</Badge>
|
|
393
438
|
</TableCell>
|
|
394
439
|
<TableCell className="text-sm text-muted-foreground">
|
|
@@ -422,14 +467,14 @@ export default function EnterprisePage() {
|
|
|
422
467
|
onClick={() => handleViewDetails(account)}
|
|
423
468
|
>
|
|
424
469
|
<SquareArrowOutUpRight className="mr-2 h-4 w-4" />
|
|
425
|
-
|
|
470
|
+
{t('actions.view')}
|
|
426
471
|
</DropdownMenuItem>
|
|
427
472
|
<DropdownMenuSeparator />
|
|
428
473
|
<DropdownMenuItem
|
|
429
474
|
onClick={() => handleOpenEdit(account)}
|
|
430
475
|
>
|
|
431
476
|
<Pencil className="mr-2 h-4 w-4" />
|
|
432
|
-
|
|
477
|
+
{t('actions.edit')}
|
|
433
478
|
</DropdownMenuItem>
|
|
434
479
|
</DropdownMenuContent>
|
|
435
480
|
</DropdownMenu>
|
|
@@ -453,7 +498,9 @@ export default function EnterprisePage() {
|
|
|
453
498
|
<div className="min-w-0 flex-1">
|
|
454
499
|
<div className="mb-1 flex flex-wrap items-center gap-1.5">
|
|
455
500
|
<Badge variant={STATUS_VARIANT[account.status]}>
|
|
456
|
-
{
|
|
501
|
+
{t.has(`status.${account.status}`)
|
|
502
|
+
? t(`status.${account.status}`)
|
|
503
|
+
: account.status}
|
|
457
504
|
</Badge>
|
|
458
505
|
{account.portalEnabled && (
|
|
459
506
|
<Badge
|
|
@@ -461,7 +508,9 @@ export default function EnterprisePage() {
|
|
|
461
508
|
className="border-blue-500/20 bg-blue-500/10 px-1.5 text-blue-600"
|
|
462
509
|
>
|
|
463
510
|
<Globe className="mr-1 h-3 w-3" />
|
|
464
|
-
|
|
511
|
+
{t.has('labels.portal')
|
|
512
|
+
? t('labels.portal')
|
|
513
|
+
: 'Portal'}
|
|
465
514
|
</Badge>
|
|
466
515
|
)}
|
|
467
516
|
</div>
|
|
@@ -491,14 +540,14 @@ export default function EnterprisePage() {
|
|
|
491
540
|
onClick={() => handleViewDetails(account)}
|
|
492
541
|
>
|
|
493
542
|
<SquareArrowOutUpRight className="mr-2 h-4 w-4" />
|
|
494
|
-
|
|
543
|
+
{t('actions.view')}
|
|
495
544
|
</DropdownMenuItem>
|
|
496
545
|
<DropdownMenuSeparator />
|
|
497
546
|
<DropdownMenuItem
|
|
498
547
|
onClick={() => handleOpenEdit(account)}
|
|
499
548
|
>
|
|
500
549
|
<Pencil className="mr-2 h-4 w-4" />
|
|
501
|
-
|
|
550
|
+
{t('actions.edit')}
|
|
502
551
|
</DropdownMenuItem>
|
|
503
552
|
</DropdownMenuContent>
|
|
504
553
|
</DropdownMenu>
|
|
@@ -508,7 +557,9 @@ export default function EnterprisePage() {
|
|
|
508
557
|
{/* CRM */}
|
|
509
558
|
{account.crmAccountName && (
|
|
510
559
|
<p className="truncate text-xs text-muted-foreground">
|
|
511
|
-
<span className="font-medium">
|
|
560
|
+
<span className="font-medium">
|
|
561
|
+
{t.has('labels.crm') ? t('labels.crm') : 'CRM'}:
|
|
562
|
+
</span>{' '}
|
|
512
563
|
{account.crmAccountName}
|
|
513
564
|
</p>
|
|
514
565
|
)}
|
|
@@ -521,7 +572,7 @@ export default function EnterprisePage() {
|
|
|
521
572
|
{account.classesCount}
|
|
522
573
|
</span>
|
|
523
574
|
<span className="text-[10px] text-muted-foreground">
|
|
524
|
-
Classes
|
|
575
|
+
{t.has('table.classes') ? t('table.classes') : 'Classes'}
|
|
525
576
|
</span>
|
|
526
577
|
</div>
|
|
527
578
|
<div className="flex flex-col py-2">
|
|
@@ -530,7 +581,7 @@ export default function EnterprisePage() {
|
|
|
530
581
|
{account.coursesCount}
|
|
531
582
|
</span>
|
|
532
583
|
<span className="text-[10px] text-muted-foreground">
|
|
533
|
-
|
|
584
|
+
{t('table.activeCourses')}
|
|
534
585
|
</span>
|
|
535
586
|
</div>
|
|
536
587
|
<div className="flex flex-col py-2">
|
|
@@ -539,14 +590,15 @@ export default function EnterprisePage() {
|
|
|
539
590
|
{account.usersCount}
|
|
540
591
|
</span>
|
|
541
592
|
<span className="text-[10px] text-muted-foreground">
|
|
542
|
-
Users
|
|
593
|
+
{t.has('table.users') ? t('table.users') : 'Users'}
|
|
543
594
|
</span>
|
|
544
595
|
</div>
|
|
545
596
|
</div>
|
|
546
597
|
|
|
547
598
|
{/* Footer */}
|
|
548
599
|
<p className="text-right text-[10px] text-muted-foreground/60">
|
|
549
|
-
|
|
600
|
+
{(t.has('labels.updated') ? t('labels.updated') : 'Updated') +
|
|
601
|
+
' '}
|
|
550
602
|
{formatDate(
|
|
551
603
|
account.updatedAt,
|
|
552
604
|
getSettingValue,
|