diff --git a/apps/web/src/routes/(dashboard)/pedidos/planejamento/+page.svelte b/apps/web/src/routes/(dashboard)/pedidos/planejamento/+page.svelte
index 6303291..60af1f3 100644
--- a/apps/web/src/routes/(dashboard)/pedidos/planejamento/+page.svelte
+++ b/apps/web/src/routes/(dashboard)/pedidos/planejamento/+page.svelte
@@ -6,7 +6,7 @@
import PageShell from '$lib/components/layout/PageShell.svelte';
import TableCard from '$lib/components/ui/TableCard.svelte';
import { useConvexClient, useQuery } from 'convex-svelte';
- import { ClipboardList, Eye, Plus, X } from 'lucide-svelte';
+ import { ClipboardList, Eye, Plus, X, Copy } from 'lucide-svelte';
import { resolve } from '$app/paths';
import { goto } from '$app/navigation';
import { toast } from 'svelte-sonner';
@@ -60,11 +60,31 @@
descricao: '',
data: '',
responsavelId: '' as string,
- acaoId: '' as string
+ acaoId: '' as string,
+ sourcePlanningId: '' as string
});
function openCreate() {
- form = { titulo: '', descricao: '', data: '', responsavelId: '', acaoId: '' };
+ form = {
+ titulo: '',
+ descricao: '',
+ data: '',
+ responsavelId: '',
+ acaoId: '',
+ sourcePlanningId: ''
+ };
+ showCreate = true;
+ }
+
+ function openClone(planning: (typeof planejamentos)[0]) {
+ form = {
+ titulo: `${planning.titulo} (Cópia)`,
+ descricao: planning.descricao,
+ data: planning.data,
+ responsavelId: planning.responsavelId,
+ acaoId: planning.acaoId || '',
+ sourcePlanningId: planning._id
+ };
showCreate = true;
}
@@ -85,7 +105,11 @@
descricao: form.descricao,
data: form.data,
responsavelId: form.responsavelId as Id<'funcionarios'>,
- acaoId: form.acaoId ? (form.acaoId as Id<'acoes'>) : undefined
+
+ acaoId: form.acaoId ? (form.acaoId as Id<'acoes'>) : undefined,
+ sourcePlanningId: form.sourcePlanningId
+ ? (form.sourcePlanningId as Id<'planejamentosPedidos'>)
+ : undefined
});
toast.success('Planejamento criado.');
showCreate = false;
@@ -184,14 +208,24 @@
-
-
- Abrir
-
+
+
+
+ Abrir
+
+
+
|
{/each}
@@ -214,7 +248,9 @@
- Novo planejamento
+
+ {form.sourcePlanningId ? 'Clonar planejamento' : 'Novo planejamento'}
+
@@ -299,7 +335,13 @@
{#if creating}
{/if}
- {creating ? 'Criando...' : 'Criar'}
+ {creating
+ ? form.sourcePlanningId
+ ? 'Clonando...'
+ : 'Criando...'
+ : form.sourcePlanningId
+ ? 'Clonar'
+ : 'Criar'}
diff --git a/apps/web/src/routes/(dashboard)/pedidos/planejamento/[id]/+page.svelte b/apps/web/src/routes/(dashboard)/pedidos/planejamento/[id]/+page.svelte
index 42f5ff5..8e9e23e 100644
--- a/apps/web/src/routes/(dashboard)/pedidos/planejamento/[id]/+page.svelte
+++ b/apps/web/src/routes/(dashboard)/pedidos/planejamento/[id]/+page.svelte
@@ -7,8 +7,9 @@
import { useConvexClient, useQuery } from 'convex-svelte';
import { page } from '$app/state';
import { resolve } from '$app/paths';
+ import { goto } from '$app/navigation';
import { toast } from 'svelte-sonner';
- import { Plus, Trash2, X, Save, Edit } from 'lucide-svelte';
+ import { Plus, Trash2, X, Save, Edit, Copy } from 'lucide-svelte';
const client = useConvexClient();
const planejamentoId = $derived(page.params.id as Id<'planejamentosPedidos'>);
@@ -323,6 +324,63 @@
gerando = false;
}
}
+
+ // --- Clone/Create Modal logic (duplicated from list page for now) ---
+ let showCreate = $state(false);
+ let creating = $state(false);
+ let createForm = $state({
+ titulo: '',
+ descricao: '',
+ data: '',
+ responsavelId: '' as string,
+ acaoId: '' as string,
+ sourcePlanningId: '' as string
+ });
+
+ function openClone() {
+ if (!planejamento) return;
+ createForm = {
+ titulo: `${planejamento.titulo} (Cópia)`,
+ descricao: planejamento.descricao,
+ data: planejamento.data,
+ responsavelId: planejamento.responsavelId,
+ acaoId: planejamento.acaoId || '',
+ sourcePlanningId: planejamento._id
+ };
+ showCreate = true;
+ }
+
+ function closeCreate() {
+ showCreate = false;
+ }
+
+ async function handleCreate() {
+ if (!createForm.titulo.trim()) return toast.error('Informe um título.');
+ if (!createForm.descricao.trim()) return toast.error('Informe uma descrição.');
+ if (!createForm.data.trim()) return toast.error('Informe uma data.');
+ if (!createForm.responsavelId) return toast.error('Selecione um responsável.');
+
+ creating = true;
+ try {
+ const id = await client.mutation(api.planejamentos.create, {
+ titulo: createForm.titulo,
+ descricao: createForm.descricao,
+ data: createForm.data,
+ responsavelId: createForm.responsavelId as Id<'funcionarios'>,
+ acaoId: createForm.acaoId ? (createForm.acaoId as Id<'acoes'>) : undefined,
+ sourcePlanningId: createForm.sourcePlanningId
+ ? (createForm.sourcePlanningId as Id<'planejamentosPedidos'>)
+ : undefined
+ });
+ toast.success('Planejamento clonado com sucesso.');
+ showCreate = false;
+ await goto(resolve(`/pedidos/planejamento/${id}`));
+ } catch (e) {
+ toast.error((e as Error).message);
+ } finally {
+ creating = false;
+ }
+ }
@@ -375,6 +433,10 @@
+
{#if isRascunho}
{#if editingHeader}
@@ -803,9 +865,9 @@
-
+
-
+
+ {/if}
+
+ {#if showCreate}
+
+
+
+
+
Clonar planejamento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{/if}
diff --git a/packages/backend/convex/planejamentos.ts b/packages/backend/convex/planejamentos.ts
index e00f272..4eb0c1c 100644
--- a/packages/backend/convex/planejamentos.ts
+++ b/packages/backend/convex/planejamentos.ts
@@ -177,7 +177,8 @@ export const create = mutation({
descricao: v.string(),
data: v.string(),
responsavelId: v.id('funcionarios'),
- acaoId: v.optional(v.id('acoes'))
+ acaoId: v.optional(v.id('acoes')),
+ sourcePlanningId: v.optional(v.id('planejamentosPedidos'))
},
returns: v.id('planejamentosPedidos'),
handler: async (ctx, args) => {
@@ -192,7 +193,7 @@ export const create = mutation({
if (!descricao) throw new Error('Informe uma descrição.');
if (!data) throw new Error('Informe uma data.');
- return await ctx.db.insert('planejamentosPedidos', {
+ const newItemId = await ctx.db.insert('planejamentosPedidos', {
titulo,
descricao,
data,
@@ -203,6 +204,30 @@ export const create = mutation({
criadoEm: now,
atualizadoEm: now
});
+
+ const sourcePlanningId = args.sourcePlanningId;
+
+ if (sourcePlanningId) {
+ const sourceItems = await ctx.db
+ .query('planejamentoItens')
+ .withIndex('by_planejamentoId', (q) => q.eq('planejamentoId', sourcePlanningId))
+ .collect();
+
+ for (const item of sourceItems) {
+ await ctx.db.insert('planejamentoItens', {
+ planejamentoId: newItemId,
+ objetoId: item.objetoId,
+ quantidade: item.quantidade,
+ valorEstimado: item.valorEstimado,
+ numeroDfd: item.numeroDfd,
+ // Não copiamos o pedidoId pois é um novo planejamento
+ criadoEm: now,
+ atualizadoEm: now
+ });
+ }
+ }
+
+ return newItemId;
}
});