@nebulit/embuilder 0.1.39
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/README.md +254 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +138 -0
- package/package.json +49 -0
- package/templates/.claude/hooks/QUICKSTART.md +256 -0
- package/templates/.claude/hooks/README.md +533 -0
- package/templates/.claude/hooks/analyze-commit.sh +22 -0
- package/templates/.claude/hooks/analyze-commit.ts +518 -0
- package/templates/.claude/hooks/analyzers/README.md +198 -0
- package/templates/.claude/hooks/analyzers/code-quality-checker.ts +154 -0
- package/templates/.claude/hooks/analyzers/code-quality.md +54 -0
- package/templates/.claude/hooks/analyzers/commit-blocker-example.ts.disabled +110 -0
- package/templates/.claude/hooks/analyzers/commit-policy.md +49 -0
- package/templates/.claude/hooks/analyzers/event-model-validator.md +49 -0
- package/templates/.claude/hooks/analyzers/event-model-validator.ts +169 -0
- package/templates/.claude/hooks/analyzers/example-logger.ts +70 -0
- package/templates/.claude/hooks/analyzers/slice-scope-validator.md +81 -0
- package/templates/.claude/hooks/check-review-result.sh +47 -0
- package/templates/.claude/hooks/prepare-review.sh +34 -0
- package/templates/.claude/hooks/review-agent-prompt.md +42 -0
- package/templates/.claude/hooks/run-review-agent.sh +124 -0
- package/templates/.claude/settings.local.json +37 -0
- package/templates/.claude/skills/help/README.md +84 -0
- package/templates/.claude/skills/help/SKILL.md +393 -0
- package/templates/.claude/skills/help/templates/demo-config.json +6753 -0
- package/templates/.claude/skills/sample-slices/SKILL.md +8 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/code-slice.json +124 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/slice.json +255 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/availablebooks/slice.json +107 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/index.json +20 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +979 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +529 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +1072 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +394 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +88 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +264 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +308 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +358 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +203 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +876 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +560 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +708 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +399 -0
- package/templates/.claude/skills/sample-slices/templates/index.json +108 -0
- package/templates/.claude/skills/slice-automation/SKILL.md +49 -0
- package/templates/.claude/skills/slice-state-change/SKILL.md +369 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocation.test.ts.sample +76 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocationCommand.ts.sample +84 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/routes.ts.sample +73 -0
- package/templates/.claude/skills/slice-state-change/templates/README.md +46 -0
- package/templates/.claude/skills/slice-state-view/SKILL.md +336 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/Locations.test.ts.sample +84 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/LocationsProjection.ts.sample +50 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/routes.ts.sample +46 -0
- package/templates/.claude/skills/slice-state-view/templates/README.md +109 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/Tables.test.ts.sample +104 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/TablesProjection.ts.sample +59 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/routes.ts.sample +46 -0
- package/templates/.claude/skills/slice-state-view/templates/V2__tables.sql +7 -0
- package/templates/.claude/skills/slice-state-view/templates/V8__locations.sql +7 -0
- package/templates/.claude/skills/test-analyzer/SKILL.md +373 -0
- package/templates/.claude/skills/test-analyzer/examples/specification-format.md +143 -0
- package/templates/.claude/skills/test-analyzer/examples/state-change-example.md +111 -0
- package/templates/.claude/skills/test-analyzer/examples/state-view-example.md +122 -0
- package/templates/AGENTS.md +110 -0
- package/templates/Claude.md +58 -0
- package/templates/README.md +178 -0
- package/templates/backend/.env +9 -0
- package/templates/backend/BACKEND_AUTH_SETUP.md +183 -0
- package/templates/backend/SWAGGER.md +213 -0
- package/templates/backend/eslint.config.mjs +31 -0
- package/templates/backend/flyway.conf +17 -0
- package/templates/backend/package.json +44 -0
- package/templates/backend/prd.json.example +64 -0
- package/templates/backend/public/assets/images/banner.png +0 -0
- package/templates/backend/public/assets/logo.png +0 -0
- package/templates/backend/public/file.svg +4 -0
- package/templates/backend/public/globe.svg +12 -0
- package/templates/backend/public/next.svg +6 -0
- package/templates/backend/public/vercel.svg +3 -0
- package/templates/backend/public/window.svg +5 -0
- package/templates/backend/server.ts +129 -0
- package/templates/backend/setup-env.sh +50 -0
- package/templates/backend/src/common/assertions.ts +6 -0
- package/templates/backend/src/common/db.ts +1 -0
- package/templates/backend/src/common/loadPostgresEventstore.ts +16 -0
- package/templates/backend/src/common/parseEndpoint.ts +51 -0
- package/templates/backend/src/common/replay.ts +9 -0
- package/templates/backend/src/common/routes.ts +19 -0
- package/templates/backend/src/common/testHelpers.ts +53 -0
- package/templates/backend/src/core/readmodel.ts +28 -0
- package/templates/backend/src/core/types.ts +26 -0
- package/templates/backend/src/process/process.ts +53 -0
- package/templates/backend/src/supabase/LoginHandler.ts +36 -0
- package/templates/backend/src/supabase/ProtectedPageProps.ts +21 -0
- package/templates/backend/src/supabase/README.md +171 -0
- package/templates/backend/src/supabase/api.ts +63 -0
- package/templates/backend/src/supabase/authMiddleware.ts +53 -0
- package/templates/backend/src/supabase/component.ts +12 -0
- package/templates/backend/src/supabase/requireUser.ts +72 -0
- package/templates/backend/src/supabase/serverProps.ts +25 -0
- package/templates/backend/src/supabase/staticProps.ts +10 -0
- package/templates/backend/src/swagger.ts +34 -0
- package/templates/backend/src/util/assertions.ts +6 -0
- package/templates/backend/supabase/config.toml +295 -0
- package/templates/backend/supabase/migrations/20260121155918593_catalogentries.sql.sample +23 -0
- package/templates/backend/supabase/seed.sql +1 -0
- package/templates/backend/tsconfig.json +31 -0
- package/templates/frontend/.env.development +3 -0
- package/templates/frontend/AGENTS.md +7 -0
- package/templates/frontend/README.md +73 -0
- package/templates/frontend/components.json +20 -0
- package/templates/frontend/eslint.config.js +26 -0
- package/templates/frontend/index.html +18 -0
- package/templates/frontend/package-lock.json +8347 -0
- package/templates/frontend/package.json +94 -0
- package/templates/frontend/postcss.config.js +6 -0
- package/templates/frontend/public/favicon.ico +0 -0
- package/templates/frontend/public/logo.png +0 -0
- package/templates/frontend/public/placeholder.svg +1 -0
- package/templates/frontend/public/robots.txt +14 -0
- package/templates/frontend/src/App.css +42 -0
- package/templates/frontend/src/App.tsx +47 -0
- package/templates/frontend/src/components/NavLink.tsx +28 -0
- package/templates/frontend/src/components/ProtectedRoute.tsx +24 -0
- package/templates/frontend/src/components/calendar/Calendar.tsx +302 -0
- package/templates/frontend/src/components/layout/DashboardLayout.tsx +21 -0
- package/templates/frontend/src/components/layout/Header.tsx +45 -0
- package/templates/frontend/src/components/layout/Sidebar.tsx +82 -0
- package/templates/frontend/src/components/tables/ReservationTemplates.tsx +189 -0
- package/templates/frontend/src/components/ui/accordion.tsx +52 -0
- package/templates/frontend/src/components/ui/alert-dialog.tsx +104 -0
- package/templates/frontend/src/components/ui/alert.tsx +43 -0
- package/templates/frontend/src/components/ui/aspect-ratio.tsx +5 -0
- package/templates/frontend/src/components/ui/avatar.tsx +38 -0
- package/templates/frontend/src/components/ui/badge.tsx +29 -0
- package/templates/frontend/src/components/ui/breadcrumb.tsx +90 -0
- package/templates/frontend/src/components/ui/button.tsx +47 -0
- package/templates/frontend/src/components/ui/calendar.tsx +54 -0
- package/templates/frontend/src/components/ui/card.tsx +43 -0
- package/templates/frontend/src/components/ui/carousel.tsx +224 -0
- package/templates/frontend/src/components/ui/chart.tsx +303 -0
- package/templates/frontend/src/components/ui/checkbox.tsx +26 -0
- package/templates/frontend/src/components/ui/collapsible.tsx +9 -0
- package/templates/frontend/src/components/ui/command.tsx +132 -0
- package/templates/frontend/src/components/ui/context-menu.tsx +178 -0
- package/templates/frontend/src/components/ui/dialog.tsx +95 -0
- package/templates/frontend/src/components/ui/drawer.tsx +87 -0
- package/templates/frontend/src/components/ui/dropdown-menu.tsx +179 -0
- package/templates/frontend/src/components/ui/form.tsx +129 -0
- package/templates/frontend/src/components/ui/hover-card.tsx +27 -0
- package/templates/frontend/src/components/ui/input-otp.tsx +61 -0
- package/templates/frontend/src/components/ui/input.tsx +22 -0
- package/templates/frontend/src/components/ui/label.tsx +17 -0
- package/templates/frontend/src/components/ui/menubar.tsx +207 -0
- package/templates/frontend/src/components/ui/navigation-menu.tsx +120 -0
- package/templates/frontend/src/components/ui/pagination.tsx +81 -0
- package/templates/frontend/src/components/ui/popover.tsx +29 -0
- package/templates/frontend/src/components/ui/progress.tsx +23 -0
- package/templates/frontend/src/components/ui/radio-group.tsx +36 -0
- package/templates/frontend/src/components/ui/resizable.tsx +37 -0
- package/templates/frontend/src/components/ui/scroll-area.tsx +38 -0
- package/templates/frontend/src/components/ui/select.tsx +143 -0
- package/templates/frontend/src/components/ui/separator.tsx +20 -0
- package/templates/frontend/src/components/ui/sheet.tsx +107 -0
- package/templates/frontend/src/components/ui/sidebar.tsx +637 -0
- package/templates/frontend/src/components/ui/skeleton.tsx +7 -0
- package/templates/frontend/src/components/ui/slider.tsx +23 -0
- package/templates/frontend/src/components/ui/sonner.tsx +27 -0
- package/templates/frontend/src/components/ui/stat-card.tsx +44 -0
- package/templates/frontend/src/components/ui/switch.tsx +27 -0
- package/templates/frontend/src/components/ui/table.tsx +72 -0
- package/templates/frontend/src/components/ui/tabs.tsx +53 -0
- package/templates/frontend/src/components/ui/textarea.tsx +21 -0
- package/templates/frontend/src/components/ui/toast.tsx +111 -0
- package/templates/frontend/src/components/ui/toaster.tsx +24 -0
- package/templates/frontend/src/components/ui/toggle-group.tsx +49 -0
- package/templates/frontend/src/components/ui/toggle.tsx +37 -0
- package/templates/frontend/src/components/ui/tooltip.tsx +28 -0
- package/templates/frontend/src/components/ui/use-toast.ts +3 -0
- package/templates/frontend/src/contexts/AuthContext.tsx +94 -0
- package/templates/frontend/src/contexts/RefreshContext.tsx +236 -0
- package/templates/frontend/src/hooks/api/index.ts +2 -0
- package/templates/frontend/src/hooks/api/useLocations.ts +15 -0
- package/templates/frontend/src/hooks/use-mobile.tsx +19 -0
- package/templates/frontend/src/hooks/use-toast.ts +186 -0
- package/templates/frontend/src/hooks/useApiContext.ts +11 -0
- package/templates/frontend/src/index.css +118 -0
- package/templates/frontend/src/integrations/supabase/client.ts +9 -0
- package/templates/frontend/src/lib/api-client.ts +136 -0
- package/templates/frontend/src/lib/api.ts +1028 -0
- package/templates/frontend/src/lib/utils.ts +6 -0
- package/templates/frontend/src/main.tsx +5 -0
- package/templates/frontend/src/pages/Auth.tsx +408 -0
- package/templates/frontend/src/pages/Dashboard.tsx +168 -0
- package/templates/frontend/src/pages/Menus.tsx +224 -0
- package/templates/frontend/src/pages/NotFound.tsx +24 -0
- package/templates/frontend/src/pages/Register.tsx +285 -0
- package/templates/frontend/src/test/example.test.ts +0 -0
- package/templates/frontend/src/test/setup.ts +15 -0
- package/templates/frontend/src/types/index.ts +8 -0
- package/templates/frontend/src/vite-env.d.ts +1 -0
- package/templates/frontend/tailwind.config.ts +101 -0
- package/templates/frontend/tsconfig.app.json +31 -0
- package/templates/frontend/tsconfig.json +16 -0
- package/templates/frontend/tsconfig.node.json +22 -0
- package/templates/frontend/vite.config.ts +21 -0
- package/templates/frontend/vitest.config.ts +16 -0
- package/templates/init.sh +1 -0
- package/templates/prompt.md +139 -0
- package/templates/ralph.sh +120 -0
- package/templates/server.mjs +505 -0
|
@@ -0,0 +1,1028 @@
|
|
|
1
|
+
// Centralized API functions
|
|
2
|
+
import {apiRequest, commandEndpoints, getApiUrl, ApiContext} from "./api-client";
|
|
3
|
+
import {supabase} from "@/integrations/supabase/client";
|
|
4
|
+
import {Location, Table, Shift, Clerk, Task, Menu, ReservationTemplate, Vacation} from "@/types";
|
|
5
|
+
import {v4} from "uuid";
|
|
6
|
+
|
|
7
|
+
// ==================== LOCATIONS ====================
|
|
8
|
+
|
|
9
|
+
interface DbLocation {
|
|
10
|
+
location_id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
zip_code: string;
|
|
13
|
+
city: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const transformDbLocation = (dbLocation: DbLocation): Location => ({
|
|
17
|
+
location_id: dbLocation.location_id,
|
|
18
|
+
name: dbLocation.name || "",
|
|
19
|
+
street: "",
|
|
20
|
+
housenumber: "",
|
|
21
|
+
zipCode: dbLocation.zip_code || "",
|
|
22
|
+
city: dbLocation.city || "",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// ==================== TENANTS ====================
|
|
26
|
+
|
|
27
|
+
export interface RegisterTenantParams {
|
|
28
|
+
tenantId: string;
|
|
29
|
+
name: string;
|
|
30
|
+
ownerId: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function registerTenant(params: RegisterTenantParams, ctx: ApiContext) {
|
|
34
|
+
const response = await apiRequest(
|
|
35
|
+
`${commandEndpoints.registerRestaurant}/${params.tenantId}`,
|
|
36
|
+
ctx,
|
|
37
|
+
{
|
|
38
|
+
method: "POST",
|
|
39
|
+
body: {
|
|
40
|
+
tenantId: params.tenantId,
|
|
41
|
+
name: params.name,
|
|
42
|
+
ownerId: params.ownerId,
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new Error(response.error);
|
|
48
|
+
}
|
|
49
|
+
return response.data;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ==================== TABLES ====================
|
|
53
|
+
|
|
54
|
+
interface DbTable {
|
|
55
|
+
table_id: string;
|
|
56
|
+
name: string;
|
|
57
|
+
seats: number;
|
|
58
|
+
blocked: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const transformDbTable = (dbTable: DbTable): Table => ({
|
|
62
|
+
tableId: dbTable.table_id,
|
|
63
|
+
name: dbTable.name || "",
|
|
64
|
+
seats: dbTable.seats || 0,
|
|
65
|
+
minPersons: 1,
|
|
66
|
+
reservable: true,
|
|
67
|
+
blocked: dbTable.blocked ?? false,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export async function fetchTables(_token: string): Promise<Table[]> {
|
|
71
|
+
const { data, error } = await supabase
|
|
72
|
+
.from("tables")
|
|
73
|
+
.select("*");
|
|
74
|
+
|
|
75
|
+
if (error) {
|
|
76
|
+
throw new Error(error.message);
|
|
77
|
+
}
|
|
78
|
+
return (data || []).map(transformDbTable);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function fetchTable(id: string, _token: string): Promise<Table | null> {
|
|
82
|
+
const { data, error } = await supabase
|
|
83
|
+
.from("tables")
|
|
84
|
+
.select("*")
|
|
85
|
+
.eq("table_id", id)
|
|
86
|
+
.single();
|
|
87
|
+
|
|
88
|
+
if (error) {
|
|
89
|
+
if (error.code === "PGRST116") return null;
|
|
90
|
+
throw new Error(error.message);
|
|
91
|
+
}
|
|
92
|
+
return data ? transformDbTable(data) : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface AddTableParams {
|
|
96
|
+
name: string;
|
|
97
|
+
seats: number;
|
|
98
|
+
minPersons?: number;
|
|
99
|
+
reservable: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function addTable(params: AddTableParams, ctx: ApiContext) {
|
|
103
|
+
const tableId = v4()
|
|
104
|
+
const response = await apiRequest(
|
|
105
|
+
`${commandEndpoints.addTable}/${tableId}`,
|
|
106
|
+
ctx,
|
|
107
|
+
{
|
|
108
|
+
method: "POST",
|
|
109
|
+
body: {
|
|
110
|
+
tableid: tableId,
|
|
111
|
+
...params,
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
throw new Error(response.error);
|
|
117
|
+
}
|
|
118
|
+
return response.data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface UpdateTableParams {
|
|
122
|
+
tableId: string;
|
|
123
|
+
name: string;
|
|
124
|
+
seats: number;
|
|
125
|
+
minPersons?: number;
|
|
126
|
+
reservable: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function updateTable(params: UpdateTableParams, ctx: ApiContext) {
|
|
130
|
+
const response = await apiRequest(
|
|
131
|
+
`${commandEndpoints.updateTable}/${params.tableId}`,
|
|
132
|
+
ctx,
|
|
133
|
+
{
|
|
134
|
+
method: "POST",
|
|
135
|
+
body: {
|
|
136
|
+
tableid: params.tableId,
|
|
137
|
+
name: params.name,
|
|
138
|
+
seats: params.seats,
|
|
139
|
+
minPersons: params.minPersons,
|
|
140
|
+
reservable: params.reservable,
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
throw new Error(response.error);
|
|
146
|
+
}
|
|
147
|
+
return response.data;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export async function removeTable(tableId: string, ctx: ApiContext) {
|
|
151
|
+
const response = await apiRequest(
|
|
152
|
+
`${commandEndpoints.removeTable}/${tableId}`,
|
|
153
|
+
ctx,
|
|
154
|
+
{
|
|
155
|
+
method: "POST",
|
|
156
|
+
body: {tableId},
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
throw new Error(response.error);
|
|
161
|
+
}
|
|
162
|
+
return response.data;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function blockTable(tableId: string, ctx: ApiContext) {
|
|
166
|
+
const response = await apiRequest(
|
|
167
|
+
`${commandEndpoints.blockTableReservation}/${tableId}`,
|
|
168
|
+
ctx,
|
|
169
|
+
{
|
|
170
|
+
method: "POST",
|
|
171
|
+
body: {tableId},
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
throw new Error(response.error);
|
|
176
|
+
}
|
|
177
|
+
return response.data;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export async function unblockTable(tableId: string, ctx: ApiContext) {
|
|
181
|
+
const response = await apiRequest(
|
|
182
|
+
`${commandEndpoints.unblockTableReservation}/${tableId}`,
|
|
183
|
+
ctx,
|
|
184
|
+
{
|
|
185
|
+
method: "POST",
|
|
186
|
+
body: {tableId},
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
throw new Error(response.error);
|
|
191
|
+
}
|
|
192
|
+
return response.data;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ==================== SHIFTS ====================
|
|
196
|
+
|
|
197
|
+
interface DbShift {
|
|
198
|
+
shift_id: string;
|
|
199
|
+
restaurant_id: string;
|
|
200
|
+
days: string[];
|
|
201
|
+
description: string;
|
|
202
|
+
start: string;
|
|
203
|
+
end: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const transformDbShift = (dbShift: DbShift): Shift => ({
|
|
207
|
+
shift_id: dbShift.shift_id,
|
|
208
|
+
restaurant_id: dbShift.restaurant_id || "",
|
|
209
|
+
description: dbShift.description || "",
|
|
210
|
+
days: Array.isArray(dbShift.days) ? dbShift.days.join(", ") : "",
|
|
211
|
+
start: dbShift.start || "",
|
|
212
|
+
end: dbShift.end || "",
|
|
213
|
+
active: true,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
export async function fetchShifts(_token: string): Promise<Shift[]> {
|
|
217
|
+
const { data, error } = await supabase
|
|
218
|
+
.from("shifts")
|
|
219
|
+
.select("*");
|
|
220
|
+
|
|
221
|
+
if (error) {
|
|
222
|
+
throw new Error(error.message);
|
|
223
|
+
}
|
|
224
|
+
return (data || []).map(transformDbShift);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export async function fetchShift(id: string, _token: string): Promise<Shift | null> {
|
|
228
|
+
const { data, error } = await supabase
|
|
229
|
+
.from("shifts")
|
|
230
|
+
.select("*")
|
|
231
|
+
.eq("shift_id", id)
|
|
232
|
+
.single();
|
|
233
|
+
|
|
234
|
+
if (error) {
|
|
235
|
+
if (error.code === "PGRST116") return null;
|
|
236
|
+
throw new Error(error.message);
|
|
237
|
+
}
|
|
238
|
+
return data ? transformDbShift(data) : null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface CreateShiftParams {
|
|
242
|
+
restaurantId: string;
|
|
243
|
+
description: string;
|
|
244
|
+
days: string[];
|
|
245
|
+
start: string;
|
|
246
|
+
end: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export async function createShift(params: CreateShiftParams, ctx: ApiContext) {
|
|
250
|
+
const shiftId = `shift-${Date.now()}`;
|
|
251
|
+
const response = await apiRequest(
|
|
252
|
+
`${commandEndpoints.createShift}/${shiftId}`,
|
|
253
|
+
ctx,
|
|
254
|
+
{
|
|
255
|
+
method: "POST",
|
|
256
|
+
body: {
|
|
257
|
+
shift_id: shiftId,
|
|
258
|
+
...params,
|
|
259
|
+
},
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
if (!response.ok) {
|
|
263
|
+
throw new Error(response.error);
|
|
264
|
+
}
|
|
265
|
+
return response.data;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export async function activateShift(restaurantId: string, shift_id: string, ctx: ApiContext) {
|
|
269
|
+
const response = await apiRequest(
|
|
270
|
+
`${commandEndpoints.activateShift}/${shift_id}`,
|
|
271
|
+
ctx,
|
|
272
|
+
{
|
|
273
|
+
method: "POST",
|
|
274
|
+
body: {restaurantId, shift_id},
|
|
275
|
+
}
|
|
276
|
+
);
|
|
277
|
+
if (!response.ok) {
|
|
278
|
+
throw new Error(response.error);
|
|
279
|
+
}
|
|
280
|
+
return response.data;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export async function deleteShift(restaurantId: string, shift_id: string, ctx: ApiContext) {
|
|
284
|
+
const response = await apiRequest(
|
|
285
|
+
`${commandEndpoints.deleteShift}/${shift_id}`,
|
|
286
|
+
ctx,
|
|
287
|
+
{
|
|
288
|
+
method: "POST",
|
|
289
|
+
body: {restaurantId, shift_id},
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
if (!response.ok) {
|
|
293
|
+
throw new Error(response.error);
|
|
294
|
+
}
|
|
295
|
+
return response.data;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface AssignShiftParams {
|
|
299
|
+
restaurantId: string;
|
|
300
|
+
shift_id: string;
|
|
301
|
+
clerkId: string;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export async function assignShift(params: AssignShiftParams, ctx: ApiContext) {
|
|
305
|
+
const assignmentId = `assign-${Date.now()}`;
|
|
306
|
+
const response = await apiRequest(
|
|
307
|
+
`${commandEndpoints.assignShift}/${assignmentId}`,
|
|
308
|
+
ctx,
|
|
309
|
+
{
|
|
310
|
+
method: "POST",
|
|
311
|
+
body: params,
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
throw new Error(response.error);
|
|
316
|
+
}
|
|
317
|
+
return response.data;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export async function unassignShift(params: AssignShiftParams, ctx: ApiContext) {
|
|
321
|
+
const unassignId = `unassign-${Date.now()}`;
|
|
322
|
+
const response = await apiRequest(
|
|
323
|
+
`${commandEndpoints.unassignShift}/${unassignId}`,
|
|
324
|
+
ctx,
|
|
325
|
+
{
|
|
326
|
+
method: "POST",
|
|
327
|
+
body: params,
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
if (!response.ok) {
|
|
331
|
+
throw new Error(response.error);
|
|
332
|
+
}
|
|
333
|
+
return response.data;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ==================== CLERKS ====================
|
|
337
|
+
|
|
338
|
+
interface DbClerk {
|
|
339
|
+
clerk_id: string;
|
|
340
|
+
email: string;
|
|
341
|
+
name: string;
|
|
342
|
+
phone: string;
|
|
343
|
+
role: string;
|
|
344
|
+
surname: string;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const transformDbClerk = (dbClerk: DbClerk): Clerk => ({
|
|
348
|
+
clerkId: dbClerk.clerk_id,
|
|
349
|
+
name: dbClerk.name || "",
|
|
350
|
+
surname: dbClerk.surname || "",
|
|
351
|
+
email: dbClerk.email || "",
|
|
352
|
+
phone: dbClerk.phone || "",
|
|
353
|
+
role: dbClerk.role || "",
|
|
354
|
+
active: true,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
export async function fetchClerks(_token: string): Promise<Clerk[]> {
|
|
358
|
+
const { data, error } = await supabase
|
|
359
|
+
.from("clerks")
|
|
360
|
+
.select("*");
|
|
361
|
+
|
|
362
|
+
if (error) {
|
|
363
|
+
throw new Error(error.message);
|
|
364
|
+
}
|
|
365
|
+
return (data || []).map(transformDbClerk);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export async function fetchClerk(id: string, _token: string): Promise<Clerk | null> {
|
|
369
|
+
const { data, error } = await supabase
|
|
370
|
+
.from("clerks")
|
|
371
|
+
.select("*")
|
|
372
|
+
.eq("clerk_id", id)
|
|
373
|
+
.single();
|
|
374
|
+
|
|
375
|
+
if (error) {
|
|
376
|
+
if (error.code === "PGRST116") return null;
|
|
377
|
+
throw new Error(error.message);
|
|
378
|
+
}
|
|
379
|
+
return data ? transformDbClerk(data) : null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export interface RegisterClerkParams {
|
|
383
|
+
name: string;
|
|
384
|
+
surname: string;
|
|
385
|
+
email: string;
|
|
386
|
+
phone: string;
|
|
387
|
+
role: string;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export async function registerClerk(params: RegisterClerkParams, ctx: ApiContext) {
|
|
391
|
+
const clerkId = v4()
|
|
392
|
+
const response = await apiRequest(
|
|
393
|
+
`${commandEndpoints.registerClerk}/${clerkId}`,
|
|
394
|
+
ctx,
|
|
395
|
+
{
|
|
396
|
+
method: "POST",
|
|
397
|
+
body: {
|
|
398
|
+
clerkId,
|
|
399
|
+
...params,
|
|
400
|
+
},
|
|
401
|
+
}
|
|
402
|
+
);
|
|
403
|
+
if (!response.ok) {
|
|
404
|
+
throw new Error(response.error);
|
|
405
|
+
}
|
|
406
|
+
return response.data;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export async function deactivateClerk(clerkId: string, ctx: ApiContext) {
|
|
410
|
+
const response = await apiRequest(
|
|
411
|
+
`${commandEndpoints.deactivateClerk}/${clerkId}`,
|
|
412
|
+
ctx,
|
|
413
|
+
{
|
|
414
|
+
method: "POST",
|
|
415
|
+
body: {clerkid: clerkId},
|
|
416
|
+
}
|
|
417
|
+
);
|
|
418
|
+
if (!response.ok) {
|
|
419
|
+
throw new Error(response.error);
|
|
420
|
+
}
|
|
421
|
+
return response.data;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export async function removeClerk(clerkId: string, ctx: ApiContext) {
|
|
425
|
+
const response = await apiRequest(
|
|
426
|
+
`${commandEndpoints.removeClerk}/${clerkId}`,
|
|
427
|
+
ctx,
|
|
428
|
+
{
|
|
429
|
+
method: "POST",
|
|
430
|
+
body: {clerkid: clerkId},
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
if (!response.ok) {
|
|
434
|
+
throw new Error(response.error);
|
|
435
|
+
}
|
|
436
|
+
return response.data;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export async function confirmInvitation(clerkId: string, ctx: ApiContext) {
|
|
440
|
+
const confirmId = `confirm-${Date.now()}`;
|
|
441
|
+
const response = await apiRequest(
|
|
442
|
+
`${commandEndpoints.confirmInvitation}/${confirmId}`,
|
|
443
|
+
ctx,
|
|
444
|
+
{
|
|
445
|
+
method: "POST",
|
|
446
|
+
body: {clerkId},
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
if (!response.ok) {
|
|
450
|
+
throw new Error(response.error);
|
|
451
|
+
}
|
|
452
|
+
return response.data;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ==================== TASKS ====================
|
|
456
|
+
|
|
457
|
+
interface DbTask {
|
|
458
|
+
task_id: string;
|
|
459
|
+
assigned_clerk: string;
|
|
460
|
+
date: string;
|
|
461
|
+
description: string;
|
|
462
|
+
interval: string;
|
|
463
|
+
repeats: string[];
|
|
464
|
+
repeat_time: string;
|
|
465
|
+
title: string;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const transformDbTask = (dbTask: DbTask): Task => ({
|
|
469
|
+
taskId: dbTask.task_id,
|
|
470
|
+
title: dbTask.title || "",
|
|
471
|
+
description: dbTask.description || "",
|
|
472
|
+
assignedClerk: dbTask.assigned_clerk || "",
|
|
473
|
+
date: dbTask.date || "",
|
|
474
|
+
interval: dbTask.interval || "",
|
|
475
|
+
repeats: Array.isArray(dbTask.repeats) ? dbTask.repeats : [],
|
|
476
|
+
repeatTime: dbTask.repeat_time || "",
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
export async function fetchTasks(_token: string): Promise<Task[]> {
|
|
480
|
+
const { data, error } = await supabase
|
|
481
|
+
.from("tasks")
|
|
482
|
+
.select("*");
|
|
483
|
+
|
|
484
|
+
if (error) {
|
|
485
|
+
throw new Error(error.message);
|
|
486
|
+
}
|
|
487
|
+
return (data || []).map(transformDbTask);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export async function fetchTask(id: string, _token: string): Promise<Task | null> {
|
|
491
|
+
const { data, error } = await supabase
|
|
492
|
+
.from("tasks")
|
|
493
|
+
.select("*")
|
|
494
|
+
.eq("task_id", id)
|
|
495
|
+
.single();
|
|
496
|
+
|
|
497
|
+
if (error) {
|
|
498
|
+
if (error.code === "PGRST116") return null;
|
|
499
|
+
throw new Error(error.message);
|
|
500
|
+
}
|
|
501
|
+
return data ? transformDbTask(data) : null;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export interface AddTaskParams {
|
|
505
|
+
title: string;
|
|
506
|
+
description: string;
|
|
507
|
+
assignedClerk: string;
|
|
508
|
+
date: string;
|
|
509
|
+
interval: string;
|
|
510
|
+
repeats: string[];
|
|
511
|
+
repeatTime: string;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export async function addTask(params: AddTaskParams, ctx: ApiContext) {
|
|
515
|
+
const taskId = v4();
|
|
516
|
+
const response = await apiRequest(
|
|
517
|
+
`${commandEndpoints.updateTask}/${taskId}`,
|
|
518
|
+
ctx,
|
|
519
|
+
{
|
|
520
|
+
method: "POST",
|
|
521
|
+
body: {
|
|
522
|
+
taskId,
|
|
523
|
+
...params,
|
|
524
|
+
},
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
if (!response.ok) {
|
|
528
|
+
throw new Error(response.error);
|
|
529
|
+
}
|
|
530
|
+
return response.data;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export interface UpdateTaskParams {
|
|
534
|
+
taskId: string;
|
|
535
|
+
title: string;
|
|
536
|
+
description: string;
|
|
537
|
+
assignedClerk: string;
|
|
538
|
+
date: string;
|
|
539
|
+
interval: string;
|
|
540
|
+
repeats: string[];
|
|
541
|
+
repeatTime: string;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export async function updateTask(params: UpdateTaskParams, ctx: ApiContext) {
|
|
545
|
+
const response = await apiRequest(
|
|
546
|
+
`${commandEndpoints.updateTask}/${params.taskId}`,
|
|
547
|
+
ctx,
|
|
548
|
+
{
|
|
549
|
+
method: "POST",
|
|
550
|
+
body: params,
|
|
551
|
+
}
|
|
552
|
+
);
|
|
553
|
+
if (!response.ok) {
|
|
554
|
+
throw new Error(response.error);
|
|
555
|
+
}
|
|
556
|
+
return response.data;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export async function deleteTask(taskId: string, ctx: ApiContext) {
|
|
560
|
+
const response = await apiRequest(
|
|
561
|
+
`${commandEndpoints.deleteTask}/${taskId}`,
|
|
562
|
+
ctx,
|
|
563
|
+
{
|
|
564
|
+
method: "POST",
|
|
565
|
+
body: {taskId},
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
if (!response.ok) {
|
|
569
|
+
throw new Error(response.error);
|
|
570
|
+
}
|
|
571
|
+
return response.data;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ==================== MENUS ====================
|
|
575
|
+
|
|
576
|
+
interface DbMenu {
|
|
577
|
+
menu_id: string;
|
|
578
|
+
file: string;
|
|
579
|
+
restaurant_id: string;
|
|
580
|
+
menu_name: string;
|
|
581
|
+
menu_type: string;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const transformDbMenu = (dbMenu: DbMenu): Menu => ({
|
|
585
|
+
menuId: dbMenu.menu_id,
|
|
586
|
+
menuName: dbMenu.menu_name || "",
|
|
587
|
+
menuType: dbMenu.menu_type || "",
|
|
588
|
+
file: dbMenu.file || "",
|
|
589
|
+
restaurant_id: dbMenu.restaurant_id || "",
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
export async function fetchMenus(_token: string): Promise<Menu[]> {
|
|
593
|
+
const { data, error } = await supabase
|
|
594
|
+
.from("uploaded_menus")
|
|
595
|
+
.select("*");
|
|
596
|
+
|
|
597
|
+
if (error) {
|
|
598
|
+
throw new Error(error.message);
|
|
599
|
+
}
|
|
600
|
+
return (data || []).map(transformDbMenu);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
export async function fetchMenu(id: string, _token: string): Promise<Menu | null> {
|
|
604
|
+
const { data, error } = await supabase
|
|
605
|
+
.from("uploaded_menus")
|
|
606
|
+
.select("*")
|
|
607
|
+
.eq("menu_id", id)
|
|
608
|
+
.single();
|
|
609
|
+
|
|
610
|
+
if (error) {
|
|
611
|
+
if (error.code === "PGRST116") return null;
|
|
612
|
+
throw new Error(error.message);
|
|
613
|
+
}
|
|
614
|
+
return data ? transformDbMenu(data) : null;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
export interface UploadMenuParams {
|
|
618
|
+
menuName: string;
|
|
619
|
+
menuType: string;
|
|
620
|
+
file: string;
|
|
621
|
+
restaurantId: string;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
export async function uploadMenu(params: UploadMenuParams, ctx: ApiContext) {
|
|
625
|
+
const menuId = `menu-${Date.now()}`;
|
|
626
|
+
const response = await apiRequest(
|
|
627
|
+
`${commandEndpoints.uploadMenu}/${menuId}`,
|
|
628
|
+
ctx,
|
|
629
|
+
{
|
|
630
|
+
method: "POST",
|
|
631
|
+
body: {
|
|
632
|
+
menuId,
|
|
633
|
+
...params,
|
|
634
|
+
},
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
if (!response.ok) {
|
|
638
|
+
throw new Error(response.error);
|
|
639
|
+
}
|
|
640
|
+
return response.data;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
export async function deleteMenu(menuId: string, ctx: ApiContext) {
|
|
644
|
+
const response = await apiRequest(
|
|
645
|
+
`${commandEndpoints.deleteMenu}/${menuId}`,
|
|
646
|
+
ctx,
|
|
647
|
+
{
|
|
648
|
+
method: "POST",
|
|
649
|
+
body: {menuId},
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
if (!response.ok) {
|
|
653
|
+
throw new Error(response.error);
|
|
654
|
+
}
|
|
655
|
+
return response.data;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// ==================== ACTIVE SHIFTS DASHBOARD ====================
|
|
659
|
+
|
|
660
|
+
interface DbActiveShiftDashboard {
|
|
661
|
+
shift_id: string;
|
|
662
|
+
name: string;
|
|
663
|
+
from_to: string;
|
|
664
|
+
assignees: string[];
|
|
665
|
+
restaurant_id: string;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const transformDbActiveShift = (db: DbActiveShiftDashboard): import("@/types").ActiveShiftDashboard => ({
|
|
669
|
+
shiftId: db.shift_id,
|
|
670
|
+
name: db.name || "",
|
|
671
|
+
fromTo: db.from_to || "",
|
|
672
|
+
assignees: Array.isArray(db.assignees) ? db.assignees : [],
|
|
673
|
+
restaurantId: db.restaurant_id || "",
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
export async function fetchActiveShiftsForDashboard(_token: string, restaurantId?: string): Promise<import("@/types").ActiveShiftDashboard[]> {
|
|
677
|
+
let query = supabase.from("active_shifts_for_dashboard").select("*");
|
|
678
|
+
if (restaurantId) {
|
|
679
|
+
query = query.eq("restaurant_id", restaurantId);
|
|
680
|
+
}
|
|
681
|
+
const { data, error } = await query;
|
|
682
|
+
if (error) {
|
|
683
|
+
throw new Error(error.message);
|
|
684
|
+
}
|
|
685
|
+
return (data || []).map(transformDbActiveShift);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// ==================== ACTIVE TASKS DASHBOARD ====================
|
|
689
|
+
|
|
690
|
+
interface DbActiveTaskDashboard {
|
|
691
|
+
task_id: string;
|
|
692
|
+
title: string;
|
|
693
|
+
description: string;
|
|
694
|
+
assigned_clerk: string;
|
|
695
|
+
date: string;
|
|
696
|
+
interval: string;
|
|
697
|
+
repeats: string[];
|
|
698
|
+
repeat_time: string;
|
|
699
|
+
restaurant_id: string;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const transformDbActiveTask = (db: DbActiveTaskDashboard): import("@/types").ActiveTaskDashboard => ({
|
|
703
|
+
taskId: db.task_id,
|
|
704
|
+
title: db.title || "",
|
|
705
|
+
description: db.description || "",
|
|
706
|
+
assignedClerk: db.assigned_clerk || "",
|
|
707
|
+
date: db.date || "",
|
|
708
|
+
interval: db.interval || "",
|
|
709
|
+
repeats: Array.isArray(db.repeats) ? db.repeats : [],
|
|
710
|
+
repeatTime: db.repeat_time || "",
|
|
711
|
+
restaurantId: db.restaurant_id || "",
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
export async function fetchActiveTasksForDashboard(_token: string, restaurantId?: string): Promise<import("@/types").ActiveTaskDashboard[]> {
|
|
715
|
+
let query = supabase.from("active_tasks_for_dashboard").select("*");
|
|
716
|
+
if (restaurantId) {
|
|
717
|
+
query = query.eq("restaurant_id", restaurantId);
|
|
718
|
+
}
|
|
719
|
+
const { data, error } = await query;
|
|
720
|
+
if (error) {
|
|
721
|
+
throw new Error(error.message);
|
|
722
|
+
}
|
|
723
|
+
return (data || []).map(transformDbActiveTask);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// ==================== RESERVATION TEMPLATES ====================
|
|
727
|
+
|
|
728
|
+
interface DbReservationTemplate {
|
|
729
|
+
template_id: string;
|
|
730
|
+
restaurant_id: string;
|
|
731
|
+
template_type: string;
|
|
732
|
+
template: string;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const transformDbReservationTemplate = (dbTemplate: DbReservationTemplate): ReservationTemplate => ({
|
|
736
|
+
templateId: dbTemplate.template_id,
|
|
737
|
+
restaurantId: dbTemplate.restaurant_id || "",
|
|
738
|
+
templateType: dbTemplate.template_type as "EMAIL" | "PHONE",
|
|
739
|
+
template: dbTemplate.template || "",
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
export async function fetchReservationTemplates(_token: string): Promise<ReservationTemplate[]> {
|
|
743
|
+
const { data, error } = await supabase
|
|
744
|
+
.from("reservation_templates")
|
|
745
|
+
.select("*");
|
|
746
|
+
|
|
747
|
+
if (error) {
|
|
748
|
+
throw new Error(error.message);
|
|
749
|
+
}
|
|
750
|
+
return (data || []).map(transformDbReservationTemplate);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
export interface SaveReservationTemplateParams {
|
|
754
|
+
templateId: string;
|
|
755
|
+
restaurantId?: string;
|
|
756
|
+
templateType: string;
|
|
757
|
+
template: string;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
export async function saveReservationTemplate(params: SaveReservationTemplateParams, ctx: ApiContext) {
|
|
761
|
+
const response = await apiRequest(
|
|
762
|
+
`/api/saveconfirmationtemplate/${params.templateId}`,
|
|
763
|
+
ctx,
|
|
764
|
+
{
|
|
765
|
+
method: "POST",
|
|
766
|
+
body: {
|
|
767
|
+
restaurantId: params.restaurantId,
|
|
768
|
+
templateType: params.templateType,
|
|
769
|
+
template: params.template,
|
|
770
|
+
},
|
|
771
|
+
}
|
|
772
|
+
);
|
|
773
|
+
if (!response.ok) {
|
|
774
|
+
throw new Error(response.error);
|
|
775
|
+
}
|
|
776
|
+
return response.data;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// ==================== VACATIONS ====================
|
|
780
|
+
|
|
781
|
+
interface DbVacation {
|
|
782
|
+
vacation_id: string;
|
|
783
|
+
restaurant_id: string;
|
|
784
|
+
from: string;
|
|
785
|
+
to: string;
|
|
786
|
+
description?: string;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const transformDbVacation = (db: DbVacation): Vacation => ({
|
|
790
|
+
vacation_id: db.vacation_id,
|
|
791
|
+
restaurant_id: db.restaurant_id || "",
|
|
792
|
+
from: db.from || "",
|
|
793
|
+
to: db.to || "",
|
|
794
|
+
description: db.description,
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
export async function fetchVacations(_token: string): Promise<Vacation[]> {
|
|
798
|
+
const { data, error } = await supabase
|
|
799
|
+
.from("planned_vacations")
|
|
800
|
+
.select("*");
|
|
801
|
+
|
|
802
|
+
if (error) {
|
|
803
|
+
throw new Error(error.message);
|
|
804
|
+
}
|
|
805
|
+
return (data || []).map(transformDbVacation);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
export interface PlanVacationParams {
|
|
809
|
+
from: string;
|
|
810
|
+
to: string;
|
|
811
|
+
description?: string;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
export async function planVacation(params: PlanVacationParams, ctx: ApiContext) {
|
|
815
|
+
const vacationId = v4();
|
|
816
|
+
const response = await apiRequest(
|
|
817
|
+
`${commandEndpoints.planVacation}/${vacationId}`,
|
|
818
|
+
ctx,
|
|
819
|
+
{
|
|
820
|
+
method: "POST",
|
|
821
|
+
body: {
|
|
822
|
+
vacation_id: vacationId,
|
|
823
|
+
from: params.from,
|
|
824
|
+
to: params.to,
|
|
825
|
+
description: params.description,
|
|
826
|
+
},
|
|
827
|
+
}
|
|
828
|
+
);
|
|
829
|
+
if (!response.ok) {
|
|
830
|
+
throw new Error(response.error);
|
|
831
|
+
}
|
|
832
|
+
return response.data;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
export async function cancelVacation(vacationId: string, ctx: ApiContext) {
|
|
836
|
+
const response = await apiRequest(
|
|
837
|
+
`${commandEndpoints.cancelVacation}/${vacationId}`,
|
|
838
|
+
ctx,
|
|
839
|
+
{
|
|
840
|
+
method: "POST",
|
|
841
|
+
body: { vacation_id: vacationId },
|
|
842
|
+
}
|
|
843
|
+
);
|
|
844
|
+
if (!response.ok) {
|
|
845
|
+
throw new Error(response.error);
|
|
846
|
+
}
|
|
847
|
+
return response.data;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// ==================== RESERVATION CANCELLATION ====================
|
|
851
|
+
|
|
852
|
+
export interface ActiveReservation {
|
|
853
|
+
reservation_id: string;
|
|
854
|
+
date: string;
|
|
855
|
+
start: string;
|
|
856
|
+
duration: number;
|
|
857
|
+
persons: number;
|
|
858
|
+
restaurant_id: string;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
export interface ReservationDetails {
|
|
862
|
+
reservation_id: string;
|
|
863
|
+
name: string;
|
|
864
|
+
email: string;
|
|
865
|
+
phone: string;
|
|
866
|
+
restaurant_id: string;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
export async function fetchActiveReservationsForCancellation(restaurantId: string): Promise<ActiveReservation[]> {
|
|
870
|
+
const { data, error } = await supabase
|
|
871
|
+
.from("active_reservations_for_cancellation")
|
|
872
|
+
.select("*")
|
|
873
|
+
.eq("restaurant_id", restaurantId);
|
|
874
|
+
|
|
875
|
+
if (error) {
|
|
876
|
+
throw new Error(error.message);
|
|
877
|
+
}
|
|
878
|
+
return data || [];
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
export async function fetchActiveReservationById(reservationId: string): Promise<ActiveReservation | null> {
|
|
882
|
+
const { data, error } = await supabase
|
|
883
|
+
.from("active_reservations_for_cancellation")
|
|
884
|
+
.select("*")
|
|
885
|
+
.eq("reservation_id", reservationId)
|
|
886
|
+
.maybeSingle();
|
|
887
|
+
|
|
888
|
+
if (error) {
|
|
889
|
+
throw new Error(error.message);
|
|
890
|
+
}
|
|
891
|
+
return data;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
export interface ReservationDetailsLookup {
|
|
895
|
+
reservation_id: string;
|
|
896
|
+
name: string;
|
|
897
|
+
email: string;
|
|
898
|
+
phone: string;
|
|
899
|
+
description:string;
|
|
900
|
+
restaurant_id: string;
|
|
901
|
+
confirmed: boolean;
|
|
902
|
+
start_date: string;
|
|
903
|
+
end_date: string;
|
|
904
|
+
showup_registered: boolean;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
export async function fetchUpcomingReservations(restaurantId: string): Promise<ReservationDetailsLookup[]> {
|
|
908
|
+
const now = new Date().toISOString();
|
|
909
|
+
const { data, error } = await supabase
|
|
910
|
+
.from("reservation_details_lookup")
|
|
911
|
+
.select("*")
|
|
912
|
+
.eq("restaurant_id", restaurantId)
|
|
913
|
+
.gt("end_date", now)
|
|
914
|
+
.order("start_date", { ascending: true });
|
|
915
|
+
|
|
916
|
+
if (error) {
|
|
917
|
+
throw new Error(error.message);
|
|
918
|
+
}
|
|
919
|
+
return data || [];
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
export async function fetchReservationDetails(restaurantId, reservationId: string): Promise<ReservationDetails | null> {
|
|
923
|
+
const { data, error } = await supabase
|
|
924
|
+
.from("reservation_details_lookup")
|
|
925
|
+
.select("*")
|
|
926
|
+
.eq("reservation_id", reservationId)
|
|
927
|
+
.eq("restaurant_id", restaurantId)
|
|
928
|
+
.maybeSingle();
|
|
929
|
+
|
|
930
|
+
if (error) {
|
|
931
|
+
throw new Error(error.message);
|
|
932
|
+
}
|
|
933
|
+
return data;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
export async function cancelReservation(reservationId: string, ctx: ApiContext) {
|
|
937
|
+
const response = await apiRequest(
|
|
938
|
+
`${commandEndpoints.cancelReservation}/${reservationId}`,
|
|
939
|
+
ctx,
|
|
940
|
+
{
|
|
941
|
+
method: "POST",
|
|
942
|
+
body: { reservationId },
|
|
943
|
+
}
|
|
944
|
+
);
|
|
945
|
+
if (!response.ok) {
|
|
946
|
+
throw new Error(response.error);
|
|
947
|
+
}
|
|
948
|
+
return response.data;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// ==================== ONLINE RESERVATION ====================
|
|
952
|
+
|
|
953
|
+
export interface OnlineReservationStatus {
|
|
954
|
+
restaurant_id: string;
|
|
955
|
+
active: boolean;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
export async function fetchOnlineReservationStatus(_token: string): Promise<OnlineReservationStatus | null> {
|
|
959
|
+
const { data, error } = await supabase
|
|
960
|
+
.from("online_reservation_status")
|
|
961
|
+
.select("*")
|
|
962
|
+
.maybeSingle();
|
|
963
|
+
|
|
964
|
+
if (error) {
|
|
965
|
+
throw new Error(error.message);
|
|
966
|
+
}
|
|
967
|
+
return data;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
export async function activateOnlineReservation(restaurantId: string, ctx: ApiContext) {
|
|
971
|
+
const response = await apiRequest(
|
|
972
|
+
`${commandEndpoints.activateOnlineReservation}/${restaurantId}`,
|
|
973
|
+
ctx,
|
|
974
|
+
{
|
|
975
|
+
method: "POST",
|
|
976
|
+
body: { restaurantId },
|
|
977
|
+
}
|
|
978
|
+
);
|
|
979
|
+
if (!response.ok) {
|
|
980
|
+
throw new Error(response.error);
|
|
981
|
+
}
|
|
982
|
+
return response.data;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
export async function deactivateOnlineReservation(restaurantId: string, ctx: ApiContext) {
|
|
986
|
+
const response = await apiRequest(
|
|
987
|
+
`${commandEndpoints.deactivateOnlineReservation}/${restaurantId}`,
|
|
988
|
+
ctx,
|
|
989
|
+
{
|
|
990
|
+
method: "POST",
|
|
991
|
+
body: { restaurantId },
|
|
992
|
+
}
|
|
993
|
+
);
|
|
994
|
+
if (!response.ok) {
|
|
995
|
+
throw new Error(response.error);
|
|
996
|
+
}
|
|
997
|
+
return response.data;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
export async function registerNoShow(reservationId: string, ctx: ApiContext) {
|
|
1001
|
+
const response = await apiRequest(
|
|
1002
|
+
`${commandEndpoints.registerNoShow}/${reservationId}`,
|
|
1003
|
+
ctx,
|
|
1004
|
+
{
|
|
1005
|
+
method: "POST",
|
|
1006
|
+
body: { reservationId },
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
if (!response.ok) {
|
|
1010
|
+
throw new Error(response.error);
|
|
1011
|
+
}
|
|
1012
|
+
return response.data;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
export async function registerShowUp(reservationId: string, ctx: ApiContext) {
|
|
1016
|
+
const response = await apiRequest(
|
|
1017
|
+
`${commandEndpoints.registerShowUp}/${reservationId}`,
|
|
1018
|
+
ctx,
|
|
1019
|
+
{
|
|
1020
|
+
method: "POST",
|
|
1021
|
+
body: { reservationId },
|
|
1022
|
+
}
|
|
1023
|
+
);
|
|
1024
|
+
if (!response.ok) {
|
|
1025
|
+
throw new Error(response.error);
|
|
1026
|
+
}
|
|
1027
|
+
return response.data;
|
|
1028
|
+
}
|