@fayz-ai/plugin-workforce 0.1.7 → 0.2.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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import React3 from 'react';
2
2
  import { createSafeDataProvider, getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core';
3
3
  import { createPluginContext, saveSchedule, registerEntityPath, useModuleNavigation, useModuleNavAccess, parseViewId, EntitlementGate, UpgradePrompt, ScheduleEditor, usePermissionOptional, adminNavigateTo, formatCurrency, PersonLink, createCrudPage } from '@fayz-ai/admin';
4
- import { ModulePage, MiniCalendar, toLocalISODate, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Badge, Button, Skeleton, resolveRangePreset, compareCodes, PageToolbar, DateRangeControl, StatTiles, StatementTable, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, Input, ModalFooter, toast, Popover, PopoverTrigger, PopoverContent, Checkbox, Avatar, AvatarFallback, AvatarImage } from '@fayz-ai/ui';
5
- import { Users, Send, CalendarDays, Plus, ExternalLink, HandCoins, AlertTriangle, CalendarCheck, Unlock, Lock, Clock, LayoutTemplate, ListTree, UserPlus, UserMinus, CakeSlice, Plane, CalendarClock, ShieldAlert, Stethoscope, ClipboardList, Trash2, Pencil, Eye, ImageOff, MapPin, ScanFace } from 'lucide-react';
4
+ import { ModulePage, FilterRail, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MiniCalendar, toLocalISODate, RailWorkspace, Badge, Button, Skeleton, resolveRangePreset, compareCodes, PageToolbar, DateRangeControl, StatTiles, StatementTable, 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, Trash2, Pencil, Eye, 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
 
@@ -109,9 +109,10 @@ function SchedulesView() {
109
109
  }
110
110
  const titulares = day?.assignments.filter((a) => a.role === "titular") ?? [];
111
111
  const pendentes = titulares.filter((a) => a.status === "pending" || a.status === "notified");
112
- return /* @__PURE__ */ jsxs("div", { className: "grid gap-6 p-6 lg:grid-cols-[320px_1fr]", children: [
113
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
114
- /* @__PURE__ */ jsx(
112
+ const rail = /* @__PURE__ */ jsx(
113
+ FilterRail,
114
+ {
115
+ before: /* @__PURE__ */ jsx(
115
116
  MiniCalendar,
116
117
  {
117
118
  selectedDate: /* @__PURE__ */ new Date(`${selectedDate}T12:00:00`),
@@ -120,64 +121,66 @@ function SchedulesView() {
120
121
  markers
121
122
  }
122
123
  ),
123
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-border p-4", children: [
124
- /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-2 text-sm font-medium", children: [
125
- /* @__PURE__ */ jsx(Users, { className: "h-4 w-4", "aria-hidden": true }),
126
- "Hor\xE1rio fixo da pessoa"
127
- ] }),
128
- /* @__PURE__ */ jsxs(Select, { value: personId, onValueChange: setPersonId, children: [
129
- /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Escolha quem" }) }),
130
- /* @__PURE__ */ jsx(SelectContent, { children: staff.map((p) => /* @__PURE__ */ jsx(SelectItem, { value: p.id, children: p.name }, p.id)) })
131
- ] }),
132
- personId && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(ScheduleEditor, { assigneeId: personId }) })
133
- ] })
134
- ] }),
135
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
136
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
137
- /* @__PURE__ */ jsxs("div", { children: [
138
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: (/* @__PURE__ */ new Date(`${selectedDate}T12:00:00`)).toLocaleDateString("pt-BR", {
139
- weekday: "long",
140
- day: "2-digit",
141
- month: "long"
142
- }) }),
143
- day && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground", children: [
144
- /* @__PURE__ */ jsx(Badge, { variant: day.status === "published" ? "success" : "warning", children: STATUS_LABEL[day.status] ?? day.status }),
145
- /* @__PURE__ */ jsxs("span", { children: [
146
- titulares.length,
147
- " titular(es) \xB7 ",
148
- pendentes.length,
149
- " pendente(s)"
150
- ] })
124
+ sections: [
125
+ {
126
+ id: "fixed-hours",
127
+ title: "Hor\xE1rio fixo da pessoa",
128
+ content: /* @__PURE__ */ jsxs(Fragment, { children: [
129
+ /* @__PURE__ */ jsxs(Select, { value: personId, onValueChange: setPersonId, children: [
130
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Escolha quem" }) }),
131
+ /* @__PURE__ */ jsx(SelectContent, { children: staff.map((p) => /* @__PURE__ */ jsx(SelectItem, { value: p.id, children: p.name }, p.id)) })
132
+ ] }),
133
+ personId && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(ScheduleEditor, { assigneeId: personId }) })
134
+ ] })
135
+ }
136
+ ]
137
+ }
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)"
151
154
  ] })
152
- ] }),
153
- day && day.status === "draft" && /* @__PURE__ */ jsxs(Button, { onClick: publish, disabled: busy, children: [
154
- /* @__PURE__ */ jsx(Send, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
155
- "Publicar escala"
156
155
  ] })
157
156
  ] }),
158
- loading ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
159
- /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }),
160
- /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" })
161
- ] }) : 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)) }) : (
162
- // O pré-requisito duro do V1, dito na tela em vez de escondido: sem
163
- // molde não existe escala.
164
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border p-8 text-center", children: [
165
- /* @__PURE__ */ jsx(CalendarDays, { className: "mx-auto mb-3 h-8 w-8 text-muted-foreground", "aria-hidden": true }),
166
- /* @__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." }),
167
- templates.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-sm items-center gap-2", children: [
168
- /* @__PURE__ */ jsxs(Select, { value: templateId, onValueChange: setTemplateId, children: [
169
- /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Molde de escala" }) }),
170
- /* @__PURE__ */ jsx(SelectContent, { children: templates.map((t) => /* @__PURE__ */ jsx(SelectItem, { value: t.id, children: t.name }, t.id)) })
171
- ] }),
172
- /* @__PURE__ */ jsxs(Button, { onClick: createFromTemplate, disabled: !templateId || busy, children: [
173
- /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
174
- "Criar"
175
- ] })
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"
176
179
  ] })
177
180
  ] })
178
- )
179
- ] })
180
- ] });
181
+ ] })
182
+ )
183
+ ] }) });
181
184
  }
182
185
  var WEEKDAYS = ["D", "S", "T", "Q", "Q", "S", "S"];
183
186
  function ShiftCard({ shift, onChanged }) {
@@ -900,8 +903,7 @@ function TimeEntriesView() {
900
903
  onPresetChange: setPreset
901
904
  }
902
905
  ),
903
- onRefresh: () => void fetchTime(from, to),
904
- storageKey: "workforce.time-entries"
906
+ onRefresh: () => void fetchTime(from, to)
905
907
  }
906
908
  ),
907
909
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
@@ -1269,6 +1271,7 @@ function PayrollCostsView() {
1269
1271
  const [rows, setRows] = React3.useState(null);
1270
1272
  const [unavailable, setUnavailable] = React3.useState(false);
1271
1273
  const [loading, setLoading] = React3.useState(true);
1274
+ const [recarga, setRecarga] = React3.useState(0);
1272
1275
  React3.useEffect(() => {
1273
1276
  let cancelled = false;
1274
1277
  setLoading(true);
@@ -1290,7 +1293,7 @@ function PayrollCostsView() {
1290
1293
  return () => {
1291
1294
  cancelled = true;
1292
1295
  };
1293
- }, [provider, from, to]);
1296
+ }, [provider, from, to, recarga]);
1294
1297
  const escopo = escopoStore.codes;
1295
1298
  const despesas = React3.useMemo(
1296
1299
  () => (rows ?? []).filter((r) => r.competenceMonth === null && r.chartAccountCode).map((r) => ({ code: r.chartAccountCode, name: r.chartAccountName })).sort((a, b) => compareCodes(a.code, b.code)),
@@ -1335,7 +1338,7 @@ function PayrollCostsView() {
1335
1338
  PageToolbar,
1336
1339
  {
1337
1340
  range: /* @__PURE__ */ jsx(DateRangeControl, { value: range, onChange: setRange, preset, onPresetChange: setPreset }),
1338
- storageKey: "workforce.payroll-costs"
1341
+ onRefresh: () => setRecarga((n) => n + 1)
1339
1342
  }
1340
1343
  ),
1341
1344
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [