@fayz-ai/plugin-workforce 0.2.18 → 0.3.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAEvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAIlD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAMzD;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,qBAAqB,CAKnE;AAMD,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACvC,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,WAAW,CAAC,EAAE,OAAO,CAAA;QACrB,EAAE,CAAC,EAAE,OAAO,CAAA;QACZ,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,CAAA;IACD,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACvC,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;IACjC,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IAEvB,sDAAsD;IACtD,YAAY,CAAC,EAAE,qBAAqB,CAAA;IAEpC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;0EACsE;IACtE,WAAW,CAAC,EAAE,SAAS,CAAA;IAEvB,sEAAsE;IACtE,WAAW,CAAC,EAAE,YAAY,CAAA;IAE1B;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACvC;AAoBD;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;CAQQ,CAAA;AA4B3C,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,cAAc,CA2HtF;AAMD,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACxD,YAAY,EACV,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,mBAAmB,EACnF,OAAO,EAAE,eAAe,EACxB,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EACpD,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,mBAAmB,EACnE,eAAe,EAAE,cAAc,EAAE,gBAAgB,GAClD,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EAAE,+BAA+B,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAEvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAIlD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAMzD;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,qBAAqB,CAKnE;AAMD,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACvC,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,WAAW,CAAC,EAAE,OAAO,CAAA;QACrB,EAAE,CAAC,EAAE,OAAO,CAAA;QACZ,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,CAAA;IACD,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACvC,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;IACjC,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IAEvB,sDAAsD;IACtD,YAAY,CAAC,EAAE,qBAAqB,CAAA;IAEpC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;0EACsE;IACtE,WAAW,CAAC,EAAE,SAAS,CAAA;IAEvB,sEAAsE;IACtE,WAAW,CAAC,EAAE,YAAY,CAAA;IAE1B;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACvC;AAoBD;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;CAQQ,CAAA;AA4B3C,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,cAAc,CAiItF;AAMD,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACxD,YAAY,EACV,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,mBAAmB,EACnF,OAAO,EAAE,eAAe,EACxB,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EACpD,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,mBAAmB,EACnE,eAAe,EAAE,cAAc,EAAE,gBAAgB,GAClD,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EAAE,+BAA+B,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import React3 from 'react';
2
- import { recordRailFields, RECORD_GROUP, activeFacet, createSafeDataProvider, getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core';
3
- import { createPluginContext, saveSchedule, registerEntityPath, useModuleNavigation, useModuleNavAccess, parseViewId, EntitlementGate, UpgradePrompt, ScheduleEditor, usePermissionOptional, adminNavigateTo, formatCurrency, PersonLink, createCrudPage, WidgetSlot } from '@fayz-ai/admin';
4
- import { ModulePage, FilterRail, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MiniCalendar, toLocalISODate, RailWorkspace, Badge, Button, Skeleton, resolveRangePreset, compareCodes, PageToolbar, DateRangeControl, StatTiles, StatementTable, PageSubNav, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, Input, ModalFooter, toast, Popover, PopoverTrigger, PopoverContent, Checkbox, Avatar, AvatarFallback, AvatarImage } from '@fayz-ai/ui';
5
- import { Send, CalendarDays, Plus, ExternalLink, HandCoins, AlertTriangle, Users, CalendarCheck, Unlock, Lock, Clock, LayoutTemplate, ListTree, UserPlus, UserMinus, CakeSlice, Plane, CalendarClock, ShieldAlert, Stethoscope, ClipboardList, FileText, ChevronRight, Trash2, Pencil, Eye, ImageOff, MapPin, ScanFace } from 'lucide-react';
2
+ import { recordRailFields, RECORD_GROUP, activeFacet, tl, createSafeDataProvider, getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core';
3
+ import { createPluginContext, defineSettingsTab, saveSchedule, registerEntityPath, useModuleNavigation, useModuleNavAccess, parseViewId, EntitlementGate, UpgradePrompt, ScheduleEditor, usePermissionOptional, adminNavigateTo, formatCurrency, PersonLink, createCrudPage, WidgetSlot } from '@fayz-ai/admin';
4
+ import { ModulePage, FilterRail, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MiniCalendar, toLocalISODate, Badge, Button, Skeleton, resolveRangePreset, compareCodes, PageToolbar, DateRangeControl, StatTiles, StatementTable, PageSubNav, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, Input, ModalFooter, toast, Popover, PopoverTrigger, PopoverContent, Checkbox, Avatar, AvatarFallback, DataTable, AvatarImage } from '@fayz-ai/ui';
5
+ import { Send, CalendarDays, Plus, ExternalLink, HandCoins, AlertTriangle, Users, CalendarCheck, Unlock, Lock, Clock, LayoutTemplate, ListTree, UserPlus, UserMinus, CakeSlice, Plane, CalendarClock, ShieldAlert, Stethoscope, ClipboardList, FileText, Pencil, Eye, ChevronRight, Trash2, ImageOff, MapPin, ScanFace } from 'lucide-react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { createStore } from 'zustand/vanilla';
8
8
 
@@ -136,51 +136,54 @@ function SchedulesView() {
136
136
  ]
137
137
  }
138
138
  );
139
- return /* @__PURE__ */ jsx(RailWorkspace, { rail, className: "p-6", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
140
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
141
- /* @__PURE__ */ jsxs("div", { children: [
142
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: (/* @__PURE__ */ new Date(`${selectedDate}T12:00:00`)).toLocaleDateString("pt-BR", {
143
- weekday: "long",
144
- day: "2-digit",
145
- month: "long"
146
- }) }),
147
- day && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground", children: [
148
- /* @__PURE__ */ jsx(Badge, { variant: day.status === "published" ? "success" : "warning", children: STATUS_LABEL[day.status] ?? day.status }),
149
- /* @__PURE__ */ jsxs("span", { children: [
150
- titulares.length,
151
- " titular(es) \xB7 ",
152
- pendentes.length,
153
- " pendente(s)"
139
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-6 p-6 lg:grid-cols-[260px_minmax(0,1fr)]", children: [
140
+ /* @__PURE__ */ jsx("aside", { className: "self-start rounded-xl border border-border bg-card p-4", children: rail }),
141
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-4", children: [
142
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
143
+ /* @__PURE__ */ jsxs("div", { children: [
144
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: (/* @__PURE__ */ new Date(`${selectedDate}T12:00:00`)).toLocaleDateString("pt-BR", {
145
+ weekday: "long",
146
+ day: "2-digit",
147
+ month: "long"
148
+ }) }),
149
+ day && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground", children: [
150
+ /* @__PURE__ */ jsx(Badge, { variant: day.status === "published" ? "success" : "warning", children: STATUS_LABEL[day.status] ?? day.status }),
151
+ /* @__PURE__ */ jsxs("span", { children: [
152
+ titulares.length,
153
+ " titular(es) \xB7 ",
154
+ pendentes.length,
155
+ " pendente(s)"
156
+ ] })
154
157
  ] })
158
+ ] }),
159
+ day && day.status === "draft" && /* @__PURE__ */ jsxs(Button, { onClick: publish, disabled: busy, children: [
160
+ /* @__PURE__ */ jsx(Send, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
161
+ "Publicar escala"
155
162
  ] })
156
163
  ] }),
157
- day && day.status === "draft" && /* @__PURE__ */ jsxs(Button, { onClick: publish, disabled: busy, children: [
158
- /* @__PURE__ */ jsx(Send, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
159
- "Publicar escala"
160
- ] })
161
- ] }),
162
- loading ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
163
- /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }),
164
- /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" })
165
- ] }) : day ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: day.assignments.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Nenhuma vaga preenchida neste dia." }) : day.assignments.map((a) => /* @__PURE__ */ jsx(AssignmentRow, { assignment: a }, a.id)) }) : (
166
- // O pré-requisito duro do V1, dito na tela em vez de escondido: sem
167
- // molde não existe escala.
168
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border p-8 text-center", children: [
169
- /* @__PURE__ */ jsx(CalendarDays, { className: "mx-auto mb-3 h-8 w-8 text-muted-foreground", "aria-hidden": true }),
170
- /* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: templates.length === 0 ? "Nenhum molde de escala cadastrado. Crie um em Templates para come\xE7ar." : "Ainda n\xE3o h\xE1 escala neste dia. Escolha um molde para mont\xE1-la." }),
171
- templates.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-sm items-center gap-2", children: [
172
- /* @__PURE__ */ jsxs(Select, { value: templateId, onValueChange: setTemplateId, children: [
173
- /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Molde de escala" }) }),
174
- /* @__PURE__ */ jsx(SelectContent, { children: templates.map((t) => /* @__PURE__ */ jsx(SelectItem, { value: t.id, children: t.name }, t.id)) })
175
- ] }),
176
- /* @__PURE__ */ jsxs(Button, { onClick: createFromTemplate, disabled: !templateId || busy, children: [
177
- /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
178
- "Criar"
164
+ loading ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
165
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }),
166
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" })
167
+ ] }) : day ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: day.assignments.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Nenhuma vaga preenchida neste dia." }) : day.assignments.map((a) => /* @__PURE__ */ jsx(AssignmentRow, { assignment: a }, a.id)) }) : (
168
+ // O pré-requisito duro do V1, dito na tela em vez de escondido: sem
169
+ // molde não existe escala.
170
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border p-8 text-center", children: [
171
+ /* @__PURE__ */ jsx(CalendarDays, { className: "mx-auto mb-3 h-8 w-8 text-muted-foreground", "aria-hidden": true }),
172
+ /* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: templates.length === 0 ? "Nenhum molde de escala cadastrado. Crie um em Templates para come\xE7ar." : "Ainda n\xE3o h\xE1 escala neste dia. Escolha um molde para mont\xE1-la." }),
173
+ templates.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-sm items-center gap-2", children: [
174
+ /* @__PURE__ */ jsxs(Select, { value: templateId, onValueChange: setTemplateId, children: [
175
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Molde de escala" }) }),
176
+ /* @__PURE__ */ jsx(SelectContent, { children: templates.map((t) => /* @__PURE__ */ jsx(SelectItem, { value: t.id, children: t.name }, t.id)) })
177
+ ] }),
178
+ /* @__PURE__ */ jsxs(Button, { onClick: createFromTemplate, disabled: !templateId || busy, children: [
179
+ /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
180
+ "Criar"
181
+ ] })
179
182
  ] })
180
183
  ] })
181
- ] })
182
- )
183
- ] }) });
184
+ )
185
+ ] })
186
+ ] });
184
187
  }
185
188
  var WEEKDAYS = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "S\xE1b"];
186
189
  var WEEKDAY_NAMES = ["Domingo", "Segunda", "Ter\xE7a", "Quarta", "Quinta", "Sexta", "S\xE1bado"];
@@ -251,7 +254,7 @@ function ShiftCard({ shift, onChanged }) {
251
254
  " (",
252
255
  r.requiredCount,
253
256
  ")",
254
- /* @__PURE__ */ jsx("button", { onClick: () => removeRequirement(r.id), "aria-label": `Remover ${r.professionName}`, children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3", "aria-hidden": true }) })
257
+ /* @__PURE__ */ jsx(Button, { variant: "bare", size: "bare", onClick: () => removeRequirement(r.id), "aria-label": `Remover ${r.professionName}`, children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3", "aria-hidden": true }) })
255
258
  ] }, r.id)) }),
256
259
  /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
257
260
  /* @__PURE__ */ jsx("div", { className: "w-full sm:w-56", children: /* @__PURE__ */ jsx(
@@ -314,11 +317,13 @@ function NewShiftModal({ template, open, onOpenChange, onChanged }) {
314
317
  /* @__PURE__ */ jsxs("div", { children: [
315
318
  /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs text-muted-foreground", children: "Dias da semana" }),
316
319
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: WEEKDAYS.map((d, i) => /* @__PURE__ */ jsx(
317
- "button",
320
+ Button,
318
321
  {
322
+ variant: "bare",
323
+ size: "bare",
319
324
  type: "button",
320
325
  onClick: () => setWeekdays((w) => w.includes(i) ? w.filter((x) => x !== i) : [...w, i]),
321
- className: `h-8 rounded px-2 text-xs ${weekdays.includes(i) ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
326
+ className: `font-normal h-8 rounded px-2 text-xs ${weekdays.includes(i) ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
322
327
  children: d
323
328
  },
324
329
  i
@@ -360,13 +365,15 @@ function TemplateBlock({ template, shifts, onChanged }) {
360
365
  function DayRow({ title, summary, empty, open, onToggle, children }) {
361
366
  return /* @__PURE__ */ jsxs("div", { className: "border-b border-border last:border-b-0", children: [
362
367
  /* @__PURE__ */ jsxs(
363
- "button",
368
+ Button,
364
369
  {
370
+ variant: "bare",
371
+ size: "bare",
365
372
  type: "button",
366
373
  onClick: onToggle,
367
374
  "aria-expanded": open,
368
375
  disabled: empty,
369
- className: "flex w-full items-center gap-3 px-3 py-2.5 text-left transition-colors hover:bg-muted/50 disabled:cursor-default disabled:hover:bg-transparent",
376
+ className: "flex w-full items-center justify-start gap-3 rounded-none px-3 py-2.5 text-left font-normal transition-colors hover:bg-muted/50 disabled:cursor-default disabled:opacity-100 disabled:hover:bg-transparent",
370
377
  children: [
371
378
  /* @__PURE__ */ jsx(
372
379
  ChevronRight,
@@ -754,54 +761,12 @@ function SeloEscala({ day }) {
754
761
  if (day.outsideSchedule) return /* @__PURE__ */ jsx(Badge, { variant: "destructive", children: "Fora da escala" });
755
762
  return /* @__PURE__ */ jsx(Badge, { variant: "success", children: "Na escala" });
756
763
  }
757
- function LinhaPessoa({ day, entries, unitName, agora, onAdjust, onDetails }) {
758
- const { currency, hourlyRate, staffLookup } = useWorkforceConfig();
764
+ function dayFacts(day, entries, hourlyRate) {
759
765
  const value = hourlyRate != null && day.workedMinutes != null && !day.reviewReason ? day.workedMinutes / 60 * hourlyRate : null;
760
766
  const alvo = entries.length ? entries[entries.length - 1] : null;
761
767
  const travado = entries.some((e) => e.payableInvoiceId);
762
768
  const retrato = entries.find((e) => e.kind === "clock_in" && e.photo) ?? entries.find((e) => e.photo) ?? null;
763
- return /* @__PURE__ */ jsxs("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [
764
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
765
- retrato ? /* @__PURE__ */ jsx(FotoDaBatida, { entry: retrato }) : /* @__PURE__ */ jsx(Avatar, { className: "h-8 w-8 shrink-0", children: /* @__PURE__ */ jsx(AvatarFallback, { children: iniciais(day.personName) }) }),
766
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
767
- /* @__PURE__ */ jsx(
768
- PersonLink,
769
- {
770
- personId: day.personId,
771
- name: day.personName ?? "Sem nome",
772
- kind: "staff",
773
- lookup: staffLookup,
774
- size: "sm",
775
- className: "text-sm"
776
- }
777
- ),
778
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Profissional" })
779
- ] })
780
- ] }) }),
781
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm text-muted-foreground", children: unitName }),
782
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm tabular-nums", children: hhmm(day.firstIn) }),
783
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm tabular-nums", children: day.isOpen ? /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Em aberto" }) : hhmm(day.lastOut) }),
784
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm tabular-nums", children: /* @__PURE__ */ jsx(Duracao, { day, agora }) }),
785
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm tabular-nums", children: value != null ? formatCurrency(value, currency) : "\u2014" }),
786
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(SeloEscala, { day }) }),
787
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
788
- travado ? (
789
- // A trava do banco, dita na tela: hora já paga não se corrige sem
790
- // reabrir a competência.
791
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 px-2 text-xs text-muted-foreground", children: [
792
- /* @__PURE__ */ jsx(Lock, { className: "h-3.5 w-3.5", "aria-hidden": true }),
793
- " j\xE1 paga"
794
- ] })
795
- ) : alvo ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: () => onAdjust(alvo), children: [
796
- /* @__PURE__ */ jsx(Pencil, { className: "mr-1 h-3.5 w-3.5", "aria-hidden": true }),
797
- " Ajustar"
798
- ] }) : null,
799
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: () => onDetails(day), children: [
800
- /* @__PURE__ */ jsx(Eye, { className: "mr-1 h-3.5 w-3.5", "aria-hidden": true }),
801
- " Detalhes"
802
- ] })
803
- ] }) })
804
- ] });
769
+ return { value, alvo, travado, retrato };
805
770
  }
806
771
  function tituloDoDia(workDate) {
807
772
  const d = /* @__PURE__ */ new Date(`${workDate}T12:00:00`);
@@ -814,12 +779,87 @@ function tituloDoDia(workDate) {
814
779
  return extenso.charAt(0).toUpperCase() + extenso.slice(1);
815
780
  }
816
781
  function GrupoDoDia({ workDate, days, entriesByPerson, unitNames, agora, onAdjust, onDetails }) {
817
- const { currency, hourlyRate } = useWorkforceConfig();
782
+ const { currency, hourlyRate, staffLookup } = useWorkforceConfig();
818
783
  const pessoas = new Set(days.map((d) => d.personId)).size;
819
784
  const abertos = days.filter((d) => d.isOpen).length;
820
785
  const revisar = days.filter((d) => d.reviewReason === "span_too_long").length;
821
786
  const minutos = days.reduce((sum, d) => sum + (d.reviewReason ? 0 : d.workedMinutes ?? 0), 0);
822
787
  const valor = hourlyRate != null ? minutos / 60 * hourlyRate : null;
788
+ const columns = React3.useMemo(() => {
789
+ const head = (label) => () => /* @__PURE__ */ jsx("span", { className: "text-xs", children: label });
790
+ const facts = (day) => dayFacts(day, entriesByPerson.get(`${day.personId}|${day.workDate}`) ?? [], hourlyRate);
791
+ return [
792
+ {
793
+ id: "name",
794
+ header: head("Nome"),
795
+ cell: ({ row: { original: day } }) => {
796
+ const { retrato } = facts(day);
797
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
798
+ retrato ? /* @__PURE__ */ jsx(FotoDaBatida, { entry: retrato }) : /* @__PURE__ */ jsx(Avatar, { className: "h-8 w-8 shrink-0", children: /* @__PURE__ */ jsx(AvatarFallback, { children: iniciais(day.personName) }) }),
799
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
800
+ /* @__PURE__ */ jsx(
801
+ PersonLink,
802
+ {
803
+ personId: day.personId,
804
+ name: day.personName ?? "Sem nome",
805
+ kind: "staff",
806
+ lookup: staffLookup,
807
+ size: "sm",
808
+ className: "text-sm"
809
+ }
810
+ ),
811
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Profissional" })
812
+ ] })
813
+ ] });
814
+ }
815
+ },
816
+ {
817
+ id: "unit",
818
+ header: head("Unidade"),
819
+ cell: ({ row: { original: day } }) => /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: day.unitId && unitNames.get(day.unitId) || "\u2014" })
820
+ },
821
+ { id: "in", header: head("Entrada"), cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: hhmm(row.original.firstIn) }) },
822
+ {
823
+ id: "out",
824
+ header: head("Sa\xEDda"),
825
+ cell: ({ row: { original: day } }) => /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: day.isOpen ? /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Em aberto" }) : hhmm(day.lastOut) })
826
+ },
827
+ { id: "duration", header: head("Dura\xE7\xE3o"), cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: /* @__PURE__ */ jsx(Duracao, { day: row.original, agora }) }) },
828
+ {
829
+ id: "value",
830
+ header: head("Valor"),
831
+ cell: ({ row: { original: day } }) => {
832
+ const { value } = facts(day);
833
+ return /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: value != null ? formatCurrency(value, currency) : "\u2014" });
834
+ }
835
+ },
836
+ { id: "schedule", header: head("Escala"), cell: ({ row }) => /* @__PURE__ */ jsx(SeloEscala, { day: row.original }) },
837
+ {
838
+ id: "actions",
839
+ header: head("A\xE7\xF5es"),
840
+ cell: ({ row: { original: day } }) => {
841
+ const { alvo, travado } = facts(day);
842
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
843
+ travado ? (
844
+ // A trava do banco, dita na tela: hora já paga não se corrige sem
845
+ // reabrir a competência.
846
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 px-2 text-xs text-muted-foreground", children: [
847
+ /* @__PURE__ */ jsx(Lock, { className: "h-3.5 w-3.5", "aria-hidden": true }),
848
+ " j\xE1 paga"
849
+ ] })
850
+ ) : alvo ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: () => onAdjust(alvo), children: [
851
+ /* @__PURE__ */ jsx(Pencil, { className: "mr-1 h-3.5 w-3.5", "aria-hidden": true }),
852
+ " Ajustar"
853
+ ] }) : null,
854
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: () => onDetails(day), children: [
855
+ /* @__PURE__ */ jsx(Eye, { className: "mr-1 h-3.5 w-3.5", "aria-hidden": true }),
856
+ " Detalhes"
857
+ ] })
858
+ ] });
859
+ }
860
+ }
861
+ ];
862
+ }, [entriesByPerson, unitNames, agora, onAdjust, onDetails, currency, hourlyRate, staffLookup]);
823
863
  return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-xl border border-border", children: [
824
864
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-4 border-l-2 border-l-primary bg-muted/40 px-4 py-3", children: [
825
865
  /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: tituloDoDia(workDate) }),
@@ -856,30 +896,7 @@ function GrupoDoDia({ workDate, days, entriesByPerson, unitNames, agora, onAdjus
856
896
  ] }),
857
897
  valor != null && valor > 0 && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-success", children: formatCurrency(valor, currency) })
858
898
  ] }),
859
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[860px] border-collapse text-left", children: [
860
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border text-xs font-medium text-muted-foreground", children: [
861
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Nome" }),
862
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Unidade" }),
863
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Entrada" }),
864
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Sa\xEDda" }),
865
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Dura\xE7\xE3o" }),
866
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Valor" }),
867
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "Escala" }),
868
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2", children: "A\xE7\xF5es" })
869
- ] }) }),
870
- /* @__PURE__ */ jsx("tbody", { children: days.map((d) => /* @__PURE__ */ jsx(
871
- LinhaPessoa,
872
- {
873
- day: d,
874
- entries: entriesByPerson.get(`${d.personId}|${d.workDate}`) ?? [],
875
- unitName: d.unitId && unitNames.get(d.unitId) || "\u2014",
876
- agora,
877
- onAdjust,
878
- onDetails
879
- },
880
- `${d.personId}|${d.workDate}`
881
- )) })
882
- ] }) })
899
+ /* @__PURE__ */ jsx(DataTable, { variant: "bare", columns, data: days, getRowId: (d) => `${d.personId}|${d.workDate}` })
883
900
  ] });
884
901
  }
885
902
  function TimeEntriesView() {
@@ -1778,11 +1795,13 @@ function Painel({ overview, upcoming, onPessoa }) {
1778
1795
  /* @__PURE__ */ jsx("div", { className: "border-b border-border bg-muted/40 px-4 py-2 text-sm font-medium", children: titulo }),
1779
1796
  itens.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-4 py-3 text-sm text-muted-foreground", children: vazio }) : /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border", children: itens.map((u, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-2 px-4 py-2 text-sm", children: [
1780
1797
  /* @__PURE__ */ jsx(
1781
- "button",
1798
+ Button,
1782
1799
  {
1800
+ variant: "bare",
1801
+ size: "bare",
1783
1802
  type: "button",
1784
1803
  onClick: () => onPessoa(u.personId),
1785
- className: "truncate text-left underline decoration-dashed decoration-muted-foreground/40 underline-offset-2 hover:text-primary",
1804
+ className: "truncate text-left underline decoration-dashed decoration-muted-foreground/40 underline-offset-2 hover:text-primary block font-normal",
1786
1805
  children: u.personName ?? "Sem nome"
1787
1806
  }
1788
1807
  ),
@@ -1971,11 +1990,10 @@ function Ficha({ personId, personName }) {
1971
1990
  children: pendencias.map((p) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-2 px-4 py-2 text-sm", children: [
1972
1991
  /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 items-center gap-2", children: [
1973
1992
  /* @__PURE__ */ jsx(
1974
- "input",
1993
+ Checkbox,
1975
1994
  {
1976
- type: "checkbox",
1977
1995
  checked: !!p.resolvedAt,
1978
- onChange: (e) => provider.resolvePendingItem(p.id, e.target.checked).then(recarregar)
1996
+ onChange: (checked) => void provider.resolvePendingItem(p.id, checked).then(recarregar)
1979
1997
  }
1980
1998
  ),
1981
1999
  /* @__PURE__ */ jsx("span", { className: `truncate ${p.resolvedAt ? "text-muted-foreground line-through" : ""}`, children: p.title })
@@ -6500,6 +6518,23 @@ var MIGRATIONS = [
6500
6518
  { id: "006_o_custo_de_pessoal_e_um_ramo_do_plano", sql: MIGRATION_006_O_CUSTO_DE_PESSOAL_E_UM_RAMO_DO_PLANO },
6501
6519
  { id: "007_a_porta_de_servico_do_ponto_fecha_tambem", sql: MIGRATION_007_A_PORTA_DE_SERVICO_DO_PONTO_FECHA_TAMBEM }
6502
6520
  ];
6521
+ var workforceV1SettingsTabs = [
6522
+ defineSettingsTab({
6523
+ id: "workforce-time-clock",
6524
+ label: tl("Time clock", "Ponto eletr\xF4nico"),
6525
+ icon: "Clock",
6526
+ section: "company",
6527
+ requiresFacet: "time_clock",
6528
+ pending: true,
6529
+ defaults: { "time_clock.unit_active": false },
6530
+ sections: [{
6531
+ description: tl("The unit password unlocks the clock-in totem for 24 hours.", "A senha da unidade libera o totem de ponto por 24 horas."),
6532
+ fields: [
6533
+ { key: "time_clock.unit_active", type: "boolean", scope: "unit", label: tl("Totem active in this unit", "Totem ativo nesta unidade") }
6534
+ ]
6535
+ }]
6536
+ })
6537
+ ];
6503
6538
 
6504
6539
  // src/index.ts
6505
6540
  function createSafeWorkforceProvider() {
@@ -6580,6 +6615,11 @@ function createWorkforcePlugin(options) {
6580
6615
  sql: m.sql,
6581
6616
  description: m.id
6582
6617
  })),
6618
+ // Paid parts a plan sells apart; their settings appear once turned on.
6619
+ facets: [
6620
+ { id: "time_clock", label: "Ponto eletr\xF4nico", description: "Registro de ponto no totem da unidade." }
6621
+ ],
6622
+ settings: workforceV1SettingsTabs,
6583
6623
  declaredFeatures: [
6584
6624
  { id: "workforce", label: config.labels.pageTitle, group: config.labels.pageTitle }
6585
6625
  ],