@hed-hog/lms 0.0.309 → 0.0.310

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.
@@ -658,7 +658,16 @@ async function applyBg(canvas: any, fabricMod: any, src: string) {
658
658
  });
659
659
  const scaleX = CANVAS_W / (img.width || 1);
660
660
  const scaleY = CANVAS_H / (img.height || 1);
661
- img.set({ scaleX, scaleY, selectable: false, evented: false });
661
+ img.set({
662
+ left: 0,
663
+ top: 0,
664
+ originX: 'left',
665
+ originY: 'top',
666
+ scaleX,
667
+ scaleY,
668
+ selectable: false,
669
+ evented: false,
670
+ });
662
671
  canvas.backgroundImage = img;
663
672
  canvas.requestRenderAll();
664
673
  } catch {
@@ -21,7 +21,7 @@ import {
21
21
  ZoomIn,
22
22
  ZoomOut,
23
23
  } from 'lucide-react';
24
- import { useCallback, useRef } from 'react';
24
+ import { useCallback, useEffect, useRef } from 'react';
25
25
  import { toast } from 'sonner';
26
26
  import { getCanvasAPI } from '../../_lib/editor/canvasInstance';
27
27
  import {
@@ -63,6 +63,49 @@ export default function Topbar({ templateContext }: TopbarProps) {
63
63
 
64
64
  const importRef = useRef<HTMLInputElement>(null);
65
65
 
66
+ const isFirstRender = useRef(true);
67
+ const autoSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
68
+ const templateContextRef = useRef(templateContext);
69
+ templateContextRef.current = templateContext;
70
+ const requestRef = useRef(request);
71
+ requestRef.current = request;
72
+
73
+ useEffect(() => {
74
+ if (isFirstRender.current) {
75
+ isFirstRender.current = false;
76
+ return;
77
+ }
78
+
79
+ localStorage.setItem(LS_KEY, JSON.stringify(templateState));
80
+
81
+ const ctx = templateContextRef.current;
82
+ if (!ctx) return;
83
+
84
+ if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
85
+
86
+ autoSaveTimerRef.current = setTimeout(() => {
87
+ requestRef
88
+ .current({
89
+ url: `/lms/certificates/templates/${ctx.id}`,
90
+ method: 'PATCH',
91
+ data: {
92
+ name: templateState.name,
93
+ slug: ctx.slug,
94
+ status: ctx.status,
95
+ templateContent: JSON.stringify(templateState),
96
+ },
97
+ })
98
+ .catch(() => {
99
+ toast.error('Falha ao salvar automaticamente');
100
+ });
101
+ }, 1500);
102
+
103
+ return () => {
104
+ if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
105
+ };
106
+ // eslint-disable-next-line react-hooks/exhaustive-deps
107
+ }, [templateState]);
108
+
66
109
  const handleNew = useCallback(() => {
67
110
  resetTemplate();
68
111
  getCanvasAPI()?.loadTemplate(useTemplateStore.getState().template);
@@ -72,7 +115,6 @@ export default function Topbar({ templateContext }: TopbarProps) {
72
115
  const handleSave = useCallback(() => {
73
116
  const run = async () => {
74
117
  if (!templateContext) {
75
- localStorage.setItem(LS_KEY, JSON.stringify(templateState));
76
118
  toast.success('Template salvo no localStorage');
77
119
  return;
78
120
  }
@@ -88,7 +130,6 @@ export default function Topbar({ templateContext }: TopbarProps) {
88
130
  },
89
131
  });
90
132
 
91
- localStorage.setItem(LS_KEY, JSON.stringify(templateState));
92
133
  toast.success('Template salvo');
93
134
  };
94
135
 
@@ -99,6 +99,7 @@ type CreateCertificateTemplatePayload = {
99
99
  type UpdateCertificateTemplatePayload = {
100
100
  name: string;
101
101
  description?: string;
102
+ status: TemplateStatus;
102
103
  };
103
104
 
104
105
  const PAGE_SIZES = [6, 12, 24];
@@ -114,6 +115,7 @@ const updateTemplateSchema = (t: (key: string) => string) =>
114
115
  z.object({
115
116
  name: z.string().trim().min(1, t('editSheet.validation.required')),
116
117
  description: z.string().trim().optional(),
118
+ status: z.enum(['draft', 'active', 'inactive']),
117
119
  });
118
120
 
119
121
  type CreateTemplateFormValues = z.infer<
@@ -173,6 +175,7 @@ export default function ModelsPage() {
173
175
  defaultValues: {
174
176
  name: '',
175
177
  description: '',
178
+ status: 'draft',
176
179
  },
177
180
  });
178
181
 
@@ -304,6 +307,7 @@ export default function ModelsPage() {
304
307
  editForm.reset({
305
308
  name: '',
306
309
  description: '',
310
+ status: 'draft',
307
311
  });
308
312
  setEditingTemplateId(null);
309
313
  }
@@ -325,6 +329,7 @@ export default function ModelsPage() {
325
329
  editForm.reset({
326
330
  name: template.name,
327
331
  description: template.description ?? '',
332
+ status: template.status,
328
333
  });
329
334
  setIsEditSheetOpen(true);
330
335
  }
@@ -410,6 +415,7 @@ export default function ModelsPage() {
410
415
  const payload: UpdateCertificateTemplatePayload = {
411
416
  name,
412
417
  description: values.description?.trim() || undefined,
418
+ status: values.status,
413
419
  };
414
420
 
415
421
  try {
@@ -825,6 +831,32 @@ export default function ModelsPage() {
825
831
  />
826
832
  </div>
827
833
 
834
+ <div className="space-y-2">
835
+ <p className="text-sm font-medium">
836
+ {t('editSheet.fields.status')}
837
+ </p>
838
+ <Controller
839
+ name="status"
840
+ control={editForm.control}
841
+ render={({ field }) => (
842
+ <Select value={field.value} onValueChange={field.onChange}>
843
+ <SelectTrigger className="w-full">
844
+ <SelectValue placeholder={t('editSheet.fields.status')} />
845
+ </SelectTrigger>
846
+ <SelectContent>
847
+ <SelectItem value="draft">{t('status.draft')}</SelectItem>
848
+ <SelectItem value="active">
849
+ {t('status.active')}
850
+ </SelectItem>
851
+ <SelectItem value="inactive">
852
+ {t('status.inactive')}
853
+ </SelectItem>
854
+ </SelectContent>
855
+ </Select>
856
+ )}
857
+ />
858
+ </div>
859
+
828
860
  {editForm.formState.errors.name?.message ? (
829
861
  <p className="text-sm text-destructive">
830
862
  {editForm.formState.errors.name.message}
@@ -2171,6 +2171,7 @@
2171
2171
  "cards": {
2172
2172
  "status": "Status",
2173
2173
  "updatedAt": "Updated",
2174
+ "noDescription": "No description",
2174
2175
  "actions": {
2175
2176
  "menuLabel": "More actions",
2176
2177
  "editTemplate": "Edit template",
@@ -2205,7 +2206,8 @@
2205
2206
  "description": "Update the template basic information.",
2206
2207
  "fields": {
2207
2208
  "name": "Name",
2208
- "description": "Description"
2209
+ "description": "Description",
2210
+ "status": "Status"
2209
2211
  },
2210
2212
  "placeholders": {
2211
2213
  "name": "e.g. Corporate Certificate",
@@ -2178,6 +2178,7 @@
2178
2178
  "cards": {
2179
2179
  "status": "Status",
2180
2180
  "updatedAt": "Atualizado",
2181
+ "noDescription": "Sem descrição",
2181
2182
  "actions": {
2182
2183
  "menuLabel": "Mais ações",
2183
2184
  "editTemplate": "Editar template",
@@ -2212,7 +2213,8 @@
2212
2213
  "description": "Atualize os dados básicos do template.",
2213
2214
  "fields": {
2214
2215
  "name": "Nome",
2215
- "description": "Descrição"
2216
+ "description": "Descrição",
2217
+ "status": "Status"
2216
2218
  },
2217
2219
  "placeholders": {
2218
2220
  "name": "Ex.: Certificado Corporativo",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/lms",
3
- "version": "0.0.309",
3
+ "version": "0.0.310",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -9,15 +9,15 @@
9
9
  "@nestjs/core": "^11",
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
- "@hed-hog/api-prisma": "0.0.6",
13
12
  "@hed-hog/api-types": "0.0.1",
14
- "@hed-hog/contact": "0.0.309",
13
+ "@hed-hog/api-prisma": "0.0.6",
15
14
  "@hed-hog/api-pagination": "0.0.7",
16
- "@hed-hog/core": "0.0.309",
17
- "@hed-hog/api-locale": "0.0.14",
18
15
  "@hed-hog/api": "0.0.6",
19
- "@hed-hog/finance": "0.0.309",
20
- "@hed-hog/category": "0.0.309"
16
+ "@hed-hog/contact": "0.0.310",
17
+ "@hed-hog/api-locale": "0.0.14",
18
+ "@hed-hog/finance": "0.0.310",
19
+ "@hed-hog/core": "0.0.310",
20
+ "@hed-hog/category": "0.0.310"
21
21
  },
22
22
  "exports": {
23
23
  ".": {