Compare commits

...

329 Commits
docker ... main

Author SHA1 Message Date
Renovate Bot
2b550aa60c Update dependency node to v23.6.1
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 26s
Check usage of free licenses / build-static-assets (push) Failing after 8s
Playwright Tests / test (push) Has been skipped
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 1m59s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m45s
2025-01-22 03:04:42 +00:00
Renovate Bot
c691359356 Update dependency postcss to v8.5.1
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m50s
Build Nginx-based docker image / build-static-assets (push) Successful in 30m20s
2025-01-16 04:07:16 +00:00
Renovate Bot
4e5202bdba Update dependency @types/node to v22.10.7
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Add copyright notice / copyright_notice (pull_request) Successful in 2m22s
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m36s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 4m51s
2025-01-16 03:07:47 +00:00
Renovate Bot
cdf688e8af Update pnpm to v9.15.4
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 50s
Build Nginx-based docker image / build-static-assets (push) Successful in 10m18s
2025-01-14 03:21:43 +00:00
Renovate Bot
46a686f578 Update dependency @types/node to v22.10.6
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m51s
Add copyright notice / copyright_notice (pull_request) Successful in 6m1s
Playwright Tests / test (push) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
2025-01-14 03:05:07 +00:00
5c2249621d Merge pull request 'Update copyright assignment to cover 2025 and include all contributors' (#180) from copyright-2025 into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m15s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m34s
Reviewed-on: #180
2025-01-13 20:43:00 +00:00
501bb3a81a Update copyright assignment to cover 2025 and include all contributors
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m12s
Add copyright notice / copyright_notice (pull_request) Successful in 1m32s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m2s
2025-01-13 21:36:52 +01:00
69f6fcbebe Merge pull request 'Define a button to reset the affinities of all groups' (#179) from reset-all-affinities into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m28s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m40s
Reviewed-on: #179
2025-01-13 20:31:56 +00:00
5d7c71b9ab Define a button to reset the affinities of all groups
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 26s
Add copyright notice / copyright_notice (pull_request) Successful in 29s
Build Nginx-based docker image / build-static-assets (push) Successful in 2m27s
2025-01-13 21:29:24 +01:00
0c05cf7661 Merge pull request 'Prevent duplicate groups in the tree list' (#178) from fix-dup-groups into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 22s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m11s
Reviewed-on: #178
2025-01-12 22:17:27 +00:00
f0e6ff9425 Prevent duplicate groups in the tree list
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Successful in 2m33s
Check usage of free licenses / build-static-assets (pull_request) Successful in 30s
Add copyright notice / copyright_notice (pull_request) Successful in 32s
2025-01-12 23:14:50 +01:00
20bd7f5983 Merge pull request 'Update dependency @tailwindcss/forms to v0.5.10' (#172) from renovate/tailwindcss-forms-0.x-lockfile into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 17s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m6s
Reviewed-on: #172
2025-01-12 21:47:37 +00:00
52902ff2ba Merge pull request 'Define a button to load the default affinities of a group' (#177) from affinity-reset into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m29s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m42s
Reviewed-on: #177
2025-01-12 21:27:56 +00:00
c233cb60de Define a button to load the default affinities of a group
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 2m0s
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m18s
Build Nginx-based docker image / build-static-assets (push) Successful in 7m19s
2025-01-12 20:54:41 +01:00
Renovate Bot
44ba54db95 Update dependency @tailwindcss/forms to v0.5.10
All checks were successful
Build Nginx-based docker image / build-static-assets (push) Successful in 4m45s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m20s
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 2m26s
2025-01-11 03:11:24 +00:00
Renovate Bot
be4f9caec7 Update dependency uuid to v11.0.5
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 5m1s
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m4s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m34s
Build Nginx-based docker image / build-static-assets (push) Successful in 17m51s
2025-01-10 03:05:58 +00:00
Renovate Bot
190118a0d1 Update dependency node to v23.6.0
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 4m29s
Build Nginx-based docker image / build-static-assets (push) Successful in 21m6s
2025-01-09 04:13:52 +00:00
Renovate Bot
862d1f85af Update dependency typescript to v5.7.3
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 7m16s
Add copyright notice / copyright_notice (pull_request) Successful in 8m50s
Playwright Tests / test (push) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
2025-01-09 03:05:58 +00:00
Renovate Bot
42d2b7091b Update dependency next to v15.1.4
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 5m36s
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m28s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 36s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m3s
2025-01-08 03:04:40 +00:00
Renovate Bot
7024a9ca11 Update pnpm to v9.15.3
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 4m10s
Build Nginx-based docker image / build-static-assets (push) Failing after 11m49s
2025-01-06 03:52:48 +00:00
Renovate Bot
5951440efb Update dependency uuid to v11.0.4
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m42s
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 9m39s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 5m11s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2025-01-06 03:05:06 +00:00
Renovate Bot
2cdf8aca58 Update dependency @types/node to v22.10.5
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 13m17s
Check usage of free licenses / build-static-assets (pull_request) Successful in 10m41s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 3m26s
Build Nginx-based docker image / build-static-assets (push) Successful in 14m12s
2025-01-04 03:05:49 +00:00
Renovate Bot
82ebaea275 Update dependency primereact to v10.9.1
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m28s
Build Nginx-based docker image / build-static-assets (push) Successful in 16m17s
2025-01-03 03:28:21 +00:00
Renovate Bot
ff406c35ec Update dependency @types/node to v22.10.4
Some checks are pending
Check usage of free licenses / build-static-assets (pull_request) Successful in 6m6s
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 7m40s
Build Nginx-based docker image / build-static-assets (push) Waiting to run
Check usage of free licenses / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
2025-01-03 03:05:07 +00:00
Renovate Bot
23901834bc Update dependency @types/node to v22.10.3
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m22s
Add copyright notice / copyright_notice (pull_request) Successful in 2m16s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 24s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m28s
2025-01-01 03:04:48 +00:00
f8a6f4d245 Merge pull request 'Push to the remote registry only on the main branch' (#165) from push-only-main into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 35s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m29s
Reviewed-on: #165
2024-12-29 12:22:27 +00:00
5dabecc9ed Update job name to be consistent with other jobs
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 49s
Add copyright notice / copyright_notice (pull_request) Successful in 1m6s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m13s
2024-12-29 13:16:46 +01:00
b3dc01bbb5 Build nginx image on all branches
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 43s
Add copyright notice / copyright_notice (pull_request) Successful in 50s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2024-12-29 13:14:32 +01:00
2ded8676f4 Push to the remote registry only on the main branch 2024-12-29 13:13:44 +01:00
1db83a6004 Merge pull request 'Optimize image builds by caching intermediate layers' (#164) from fix-docker-build into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 24s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m1s
Reviewed-on: #164
2024-12-29 12:11:51 +00:00
1269a1a56f Run docker images only on the main branch
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 31s
Check usage of free licenses / build-static-assets (pull_request) Successful in 48s
2024-12-29 13:10:58 +01:00
3e0fb208e2 Fix stage name and add additional stage
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 32s
Add copyright notice / copyright_notice (pull_request) Successful in 49s
Build Nginx-based docker image / build-static-assets (push) Successful in 1m38s
2024-12-29 11:37:11 +01:00
0594bf9456 Build and cache the intermediate stages
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 53s
Add copyright notice / copyright_notice (pull_request) Successful in 1m3s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m5s
2024-12-29 11:34:12 +01:00
36c9acee51 Fix location of cache-from in Docker build
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 31s
Add copyright notice / copyright_notice (pull_request) Successful in 36s
Build Nginx-based docker image / build-static-assets (push) Failing after 3m33s
2024-12-29 11:28:36 +01:00
Renovate Bot
b799a052a8 Update pnpm to v9.15.2
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m24s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m26s
2024-12-29 01:15:16 +00:00
Renovate Bot
7a402d81b9 Update dependency next to v15.1.3
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 3m52s
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m15s
Playwright Tests / test (push) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
2024-12-29 01:10:17 +00:00
c540828463 Merge pull request 'Fix build issue with types returned by the Slider component' (#162) from fix-build into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 36s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m40s
Reviewed-on: #162
2024-12-28 19:28:06 +00:00
a6b678c6ae Fix build issue with types returned by the Slider component
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 33s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m31s
2024-12-28 20:23:35 +01:00
6d35009593 Merge pull request 'Allow configuring affinity between groups' (#161) from group-affinities into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 33s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m20s
Reviewed-on: #161
2024-12-28 18:56:17 +00:00
dc735f1a2c Add copyright notice
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 43s
Add copyright notice / copyright_notice (pull_request) Successful in 47s
2024-12-28 18:53:59 +00:00
c49acf8ab6 Merge remote-tracking branch 'origin/main' into group-affinities
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 39s
Add copyright notice / copyright_notice (pull_request) Successful in 32s
2024-12-28 16:49:46 +01:00
52fb808d45 Define a dialog to configure the affinities between groups
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Failing after 34s
Add copyright notice / copyright_notice (pull_request) Failing after 34s
2024-12-28 14:18:14 +01:00
d307ff6927 Update status of the parent component 2024-12-28 13:04:01 +01:00
b7e2bbb46f Initial approach to configure affinities between groups 2024-12-28 13:00:24 +01:00
3f38a9191f Merge pull request 'Define a health endpoint for docker compose' (#160) from health-check-endpoint into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 27s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m22s
Reviewed-on: #160
2024-12-28 10:51:18 +00:00
07476221c3 Add copyright notice
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 32s
Add copyright notice / copyright_notice (pull_request) Successful in 34s
2024-12-28 10:46:08 +00:00
b1339e2ce9 Define a health endpoint for docker compose
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 22s
Check usage of free licenses / build-static-assets (pull_request) Successful in 35s
2024-12-28 11:45:22 +01:00
ff73133e05 Define a health endpoint for docker compose 2024-12-28 11:42:22 +01:00
70b023acac Merge pull request 'Update dependency next to v15.1.2' (#134) from renovate/next-15.x into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 16s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m12s
Reviewed-on: #134
2024-12-21 10:08:30 +00:00
Renovate Bot
42d02306eb Update dependency next to v15.1.2
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 2m19s
Check usage of free licenses / build-static-assets (pull_request) Successful in 29s
2024-12-21 01:07:14 +00:00
Renovate Bot
632a2f9815 Update dependency @types/react to v18.3.18
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m17s
Add copyright notice / copyright_notice (pull_request) Successful in 2m33s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m10s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m13s
2024-12-21 01:07:01 +00:00
Renovate Bot
e536fd1cd1 Update dependency node to v23.5.0
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 55s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m26s
2024-12-20 01:15:00 +00:00
Renovate Bot
6dcc87a2c2 Update pnpm to v9.15.1
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 4m13s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m55s
Playwright Tests / test (push) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
2024-12-20 01:06:51 +00:00
Renovate Bot
96c45ee175 Update dependency tailwindcss to v3.4.17
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 3m32s
Check usage of free licenses / build-static-assets (pull_request) Successful in 24s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 26s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m13s
2024-12-18 01:06:06 +00:00
Renovate Bot
fac573c69d Update dependency @types/react to v18.3.17
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m27s
Add copyright notice / copyright_notice (pull_request) Successful in 3m14s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 3m59s
Build Nginx-based docker image / build-static-assets (push) Successful in 10m24s
2024-12-17 01:06:27 +00:00
231be64e45 Merge pull request 'Display the discomfort breakdown in the tables diagram' (#154) from discomfort-breakdown into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m28s
Build Nginx-based docker image / build-static-assets (push) Successful in 8m56s
Reviewed-on: #154
2024-12-16 22:18:39 +00:00
658b94a2dc Add copyright notice
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 55s
Add copyright notice / copyright_notice (pull_request) Successful in 1m8s
2024-12-16 22:17:28 +00:00
96655bf62b Display the discomfort breakdown in the tables diagram
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 45s
Add copyright notice / copyright_notice (pull_request) Successful in 59s
2024-12-16 23:14:42 +01:00
Renovate Bot
5f9512991e Update dependency @types/react-dom to v18.3.5
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m34s
Add copyright notice / copyright_notice (pull_request) Successful in 2m7s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m26s
Build Nginx-based docker image / build-static-assets (push) Failing after 5m23s
2024-12-15 01:21:02 +00:00
ed7d51dee4 Merge pull request 'Update dependency @types/node to v22.10.2' (#152) from renovate/node-22.x into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 24s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m41s
Reviewed-on: #152
2024-12-12 08:03:43 +00:00
Renovate Bot
82dc0a3e35 Update dependency zod to v3.24.1
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 5m36s
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m4s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 3m20s
Build Nginx-based docker image / build-static-assets (push) Successful in 22m33s
2024-12-12 01:09:42 +00:00
Renovate Bot
35b42e2bb8 Update dependency @types/node to v22.10.2
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m10s
Add copyright notice / copyright_notice (pull_request) Successful in 7m8s
2024-12-12 01:08:57 +00:00
09a37675a9 Merge pull request 'Fix compilation issue' (#151) from dashboard into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 35s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m11s
Reviewed-on: #151
2024-12-11 23:20:55 +00:00
9029d756e7 Fix compilation issue
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 28s
Add copyright notice / copyright_notice (pull_request) Successful in 33s
2024-12-12 00:19:46 +01:00
93662f5903 Merge pull request 'Load dashboard information from the backend' (#150) from dashboard into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 23s
Build Nginx-based docker image / build-static-assets (push) Failing after 3m39s
Reviewed-on: #150
2024-12-11 07:45:08 +00:00
7dbfbb76b7 Load dashboard information from the backend
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 18s
Add copyright notice / copyright_notice (pull_request) Successful in 20s
2024-12-11 08:38:50 +01:00
Renovate Bot
53811299c8 Update dependency node to v23.4.0
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 2m31s
Build Nginx-based docker image / build-static-assets (push) Successful in 33m47s
2024-12-11 02:20:15 +00:00
Renovate Bot
6731dcc874 Update dependency @playwright/test to v1.49.1
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m22s
Add copyright notice / copyright_notice (pull_request) Successful in 18m42s
Check usage of free licenses / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2024-12-11 01:09:29 +00:00
c57bdec9fc Fix navigation link to the dashboard 2024-12-11 00:35:56 +01:00
6d5e57724c Merge pull request 'Fix group parsing in the guest model' (#147) from fix-guest-group-parsing into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 19s
Build Nginx-based docker image / build-static-assets (push) Successful in 2m54s
Reviewed-on: #147
2024-12-10 23:17:34 +00:00
be73e7018a Fix group parsing in the guest model
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 26s
Check usage of free licenses / build-static-assets (pull_request) Successful in 35s
2024-12-11 00:16:35 +01:00
37360264ea Merge pull request 'Render groups using a tree table' (#146) from groups-tree-table into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 33s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m1s
Reviewed-on: #146
2024-12-10 20:00:47 +00:00
c3e191982d Display groups in a treetable
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 29s
Add copyright notice / copyright_notice (pull_request) Successful in 35s
2024-12-10 20:59:17 +01:00
2b0fab797e WIP groups tree table 2024-12-10 09:23:07 +01:00
770f1854d1 Merge pull request 'Fix build' (#145) from fix-build into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m37s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m20s
Reviewed-on: #145
2024-12-10 07:44:24 +00:00
537498cb85 Fix build
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 28s
Add copyright notice / copyright_notice (pull_request) Successful in 32s
2024-12-09 20:57:30 +01:00
17b324d338 Merge pull request 'Fix compilation error' (#144) from fix-build into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 17s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m26s
Reviewed-on: #144
2024-12-09 19:12:57 +00:00
05392bc747 Fix compilation error
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 19s
Add copyright notice / copyright_notice (pull_request) Successful in 22s
2024-12-09 20:12:18 +01:00
fb1b7e7d0f Merge pull request 'Define UI to perform CRUD operations on expenses' (#143) from expenses-crud into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 38s
Build Nginx-based docker image / build-static-assets (push) Failing after 4m58s
Reviewed-on: #143
2024-12-09 18:28:48 +00:00
7de37759ca Add copyright notice
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 32s
Add copyright notice / copyright_notice (pull_request) Successful in 40s
2024-12-09 18:22:44 +00:00
79039572e7 Refactor multiple APIs into a single API and expose UI to modify
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 19s
Add copyright notice / copyright_notice (pull_request) Successful in 26s
expenses
2024-12-09 19:22:02 +01:00
283d90c707 Merge pull request 'Include slug namespace in the tables arrangements fetch endpoint' (#141) from fix-arrangements-api into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 45s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m38s
Reviewed-on: #141
2024-12-08 13:04:55 +00:00
066cab9da8 Include slug namespace in the tables arrangements fetch endpoint
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m37s
Add copyright notice / copyright_notice (pull_request) Successful in 2m10s
2024-12-08 14:02:29 +01:00
eddb1cab37 Merge pull request 'Define create and update forms and actions for groups' (#140) from groups-crud into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 31s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m6s
Reviewed-on: #140
2024-12-08 11:51:33 +00:00
fba1b81b4c Include edit and delete buttons in the groups table
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 19s
Check usage of free licenses / build-static-assets (pull_request) Successful in 29s
2024-12-08 12:50:33 +01:00
ad0b09c3df Add form to create a new group 2024-12-08 12:45:15 +01:00
98d3afcd8e Merge pull request 'Preload a CSRF token on the registration page' (#139) from preload-csrf-token into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m11s
Build Nginx-based docker image / build-static-assets (push) Successful in 10m36s
Reviewed-on: #139
2024-12-08 08:32:43 +00:00
b4cfd91ff4 Preload a CSRF token on the registration page
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 28s
Add copyright notice / copyright_notice (pull_request) Successful in 42s
2024-12-08 09:31:31 +01:00
Renovate Bot
f68587419d Update pnpm to v9.15.0
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 5m9s
Add copyright notice / copyright_notice (pull_request) Successful in 7m41s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m43s
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m17s
2024-12-08 01:08:50 +00:00
db9a6a1b83 Merge pull request 'Update the way to get params from the URL' (#136) from fix-localstorage-issue into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 55s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m20s
Reviewed-on: #136
2024-12-07 22:02:30 +00:00
b6db72a5b7 Update the way to get params from the URL
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 1m29s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m46s
2024-12-07 22:59:48 +01:00
f0bfa90140 Merge pull request 'Create a registration form' (#135) from registration-form into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 37s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m56s
Reviewed-on: #135
2024-12-07 18:13:03 +00:00
809da23b91 Add copyright notice
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m10s
Add copyright notice / copyright_notice (pull_request) Successful in 1m38s
2024-12-07 18:11:21 +00:00
054e1c6da0 Display a message after successful submission of registration form
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m40s
Add copyright notice / copyright_notice (pull_request) Successful in 2m9s
2024-12-07 19:06:24 +01:00
4d576b07da Basic error validation in the form 2024-12-07 18:33:22 +01:00
d085a2ab19 Display a captcha in the registration form 2024-12-07 13:06:14 +01:00
Renovate Bot
12fe9b5b80 Update dependency tailwindcss to v3.4.16
Some checks failed
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 2m42s
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m14s
Playwright Tests / test (push) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Failing after 6m53s
Check usage of free licenses / build-static-assets (push) Failing after 10m39s
2024-12-04 01:07:30 +00:00
59b51885d3 Merge pull request 'Restore function removed by bad merge' (#129) from fix/bad-merge into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 22s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m18s
Reviewed-on: #129
2024-12-01 22:00:03 +00:00
0620516a05 Restore function removed by bad merge
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 31s
Check usage of free licenses / build-static-assets (pull_request) Successful in 36s
2024-12-01 22:59:07 +01:00
9aab22ab39 Merge pull request 'Simplify guest edition by adding status to the dialog' (#112) from edit-guest-status into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 25s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m26s
Reviewed-on: #112
2024-12-01 19:47:21 +00:00
d25622d764 Merge remote-tracking branch 'origin/main' into edit-guest-status
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 19s
Check usage of free licenses / build-static-assets (pull_request) Successful in 24s
2024-12-01 20:46:48 +01:00
154f1975f6 Merge pull request 'Update pnpm to v9.14.4' (#125) from renovate/pnpm-9.x into main
All checks were successful
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m10s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m59s
Reviewed-on: #125
2024-12-01 19:11:00 +00:00
1908b76822 Merge pull request 'Define a basic login form with redirection to the Dashboard' (#127) from login-register-forms into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
Reviewed-on: #127
2024-12-01 19:10:35 +00:00
5d5d415904 Merge branch 'main' into login-register-forms
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m27s
Add copyright notice / copyright_notice (pull_request) Successful in 1m38s
2024-12-01 19:08:54 +00:00
437d4faddc Merge pull request 'Disable execution of Playwright tests' (#128) from disable-playwright into main
Some checks failed
Playwright Tests / test (push) Has been skipped
Check usage of free licenses / build-static-assets (push) Successful in 1m2s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #128
2024-12-01 19:08:44 +00:00
dd6b84ec05 Disable execution of Playwright tests
All checks were successful
Playwright Tests / test (pull_request) Has been skipped
Add copyright notice / copyright_notice (pull_request) Successful in 38s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m30s
2024-12-01 20:06:33 +01:00
15ef451966 Add slug prefix to Playwright specs
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m11s
Add copyright notice / copyright_notice (pull_request) Successful in 2m5s
Playwright Tests / test (pull_request) Failing after 10m5s
2024-12-01 18:24:01 +01:00
82f5dd6c64 Update navigation to accept the slug as part of the URL
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 44s
Add copyright notice / copyright_notice (pull_request) Successful in 54s
Playwright Tests / test (pull_request) Failing after 8m28s
2024-12-01 18:02:25 +01:00
0ef310fecd Use Accept header to avoid unnecessary call to get current user 2024-12-01 17:47:42 +01:00
868f950559 Display email of current user 2024-12-01 17:33:33 +01:00
7697148b7d Basic logout flow 2024-12-01 17:33:33 +01:00
989820e41b Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m11s
Add copyright notice / copyright_notice (pull_request) Successful in 1m30s
Playwright Tests / test (pull_request) Successful in 3m38s
2024-12-01 15:33:24 +00:00
9b3443addf Define a basic login form with redirection to the Dashboard
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 47s
Add copyright notice / copyright_notice (pull_request) Successful in 1m2s
Playwright Tests / test (pull_request) Successful in 4m32s
2024-12-01 16:31:56 +01:00
Renovate Bot
bb403fd512 Update pnpm to v9.14.4
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 3m55s
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m19s
Playwright Tests / test (pull_request) Successful in 7m21s
2024-12-01 01:08:40 +00:00
15144b478e Merge pull request 'Update API routes to target the default tenant' (#126) from default-tenant into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m13s
Playwright Tests / test (push) Successful in 4m7s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m29s
Reviewed-on: #126
2024-11-30 20:01:23 +00:00
3385230353 Adapt Playwright mocks to use the new URL
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 33s
Add copyright notice / copyright_notice (pull_request) Successful in 40s
Playwright Tests / test (pull_request) Successful in 3m1s
2024-11-30 20:58:17 +01:00
54be5515e5 Update API routes to target the default tenant
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 29s
Add copyright notice / copyright_notice (pull_request) Successful in 32s
Playwright Tests / test (pull_request) Failing after 5m1s
2024-11-30 20:21:19 +01:00
e12887e79f Merge pull request 'Update dependency primereact to v10.8.5' (#124) from renovate/primereact-10.x-lockfile into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 11s
Check usage of free licenses / build-static-assets (push) Successful in 1m39s
Playwright Tests / test (push) Successful in 5m38s
Reviewed-on: #124
2024-11-29 19:36:09 +00:00
Renovate Bot
f88c14fefd Update dependency primereact to v10.8.5
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m46s
Add copyright notice / copyright_notice (pull_request) Successful in 3m36s
Playwright Tests / test (pull_request) Successful in 7m4s
2024-11-29 01:06:59 +00:00
Renovate Bot
7846dddb60 Update dependency @types/node to v22.10.1
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 3m39s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m42s
Playwright Tests / test (pull_request) Successful in 10m15s
Check usage of free licenses / build-static-assets (push) Successful in 3m53s
Playwright Tests / test (push) Successful in 8m17s
Build Nginx-based docker image / build-static-assets (push) Successful in 22m40s
2024-11-29 01:06:45 +00:00
9f56663217 Merge pull request 'Update dependency @types/node to v22.10.0' (#122) from renovate/node-22.x into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m12s
Playwright Tests / test (push) Successful in 3m22s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m11s
Reviewed-on: #122
2024-11-27 09:51:44 +00:00
Renovate Bot
4f3446eb57 Update dependency @types/node to v22.10.0
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m53s
Add copyright notice / copyright_notice (pull_request) Successful in 4m2s
Playwright Tests / test (pull_request) Successful in 11m48s
2024-11-27 01:08:49 +00:00
bf034cdf84 Merge pull request 'Update dependency typescript to v5.7.2' (#121) from renovate/typescript-5.x into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 2m17s
Playwright Tests / test (push) Successful in 8m48s
Build Nginx-based docker image / build-static-assets (push) Successful in 11m43s
Reviewed-on: #121
2024-11-26 06:26:51 +00:00
Renovate Bot
f30d0711e9 Update dependency typescript to v5.7.2
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 4m8s
Check usage of free licenses / build-static-assets (pull_request) Successful in 55s
Playwright Tests / test (pull_request) Successful in 6m54s
2024-11-25 01:10:19 +00:00
Renovate Bot
04b22efa36 Update pnpm to v9.14.2
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 4m57s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m57s
Playwright Tests / test (pull_request) Successful in 12m33s
Check usage of free licenses / build-static-assets (push) Successful in 1m5s
Playwright Tests / test (push) Failing after 25m44s
Build Nginx-based docker image / build-static-assets (push) Successful in 52m53s
2024-11-25 01:09:59 +00:00
Renovate Bot
4c0d3aedaf Update dependency node to v23.3.0
Some checks failed
Check usage of free licenses / build-static-assets (push) Failing after 28s
Playwright Tests / test (push) Failing after 29s
Build Nginx-based docker image / build-static-assets (push) Failing after 30s
2024-11-24 02:53:50 +00:00
Renovate Bot
62662789e8 Update dependency @types/node to v22.9.3
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 6m53s
Check usage of free licenses / build-static-assets (pull_request) Successful in 6m32s
Playwright Tests / test (pull_request) Successful in 31m52s
Build Nginx-based docker image / build-static-assets (push) Failing after 4s
Check usage of free licenses / build-static-assets (push) Failing after 15s
Playwright Tests / test (push) Failing after 11s
2024-11-24 01:06:03 +00:00
Renovate Bot
7134150a81 Update dependency @heroicons/react to v2.2.0
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m21s
Add copyright notice / copyright_notice (pull_request) Successful in 3m37s
Playwright Tests / test (pull_request) Successful in 13m48s
Check usage of free licenses / build-static-assets (push) Successful in 2m58s
Playwright Tests / test (push) Successful in 8m3s
Build Nginx-based docker image / build-static-assets (push) Failing after 9m6s
2024-11-21 01:09:06 +00:00
Renovate Bot
c8331f927e Update pnpm to v9.14.1
Some checks failed
Check usage of free licenses / build-static-assets (push) Failing after 15s
Build Nginx-based docker image / build-static-assets (push) Failing after 33s
Playwright Tests / test (push) Successful in 5m52s
2024-11-20 01:46:57 +00:00
Renovate Bot
2b9d06c670 Update dependency @types/node to v22.9.1
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 5m12s
Add copyright notice / copyright_notice (pull_request) Successful in 16m43s
Playwright Tests / test (pull_request) Successful in 21m16s
Check usage of free licenses / build-static-assets (push) Failing after 3m4s
Build Nginx-based docker image / build-static-assets (push) Failing after 3m23s
Playwright Tests / test (push) Has been cancelled
2024-11-20 01:06:15 +00:00
Renovate Bot
91484f081c Update dependency @playwright/test to v1.49.0
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m48s
Add copyright notice / copyright_notice (pull_request) Successful in 6m0s
Playwright Tests / test (pull_request) Successful in 8m36s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m59s
Check usage of free licenses / build-static-assets (push) Successful in 4m8s
Playwright Tests / test (push) Successful in 23m19s
2024-11-19 01:08:05 +00:00
5fe6031dc5 Merge pull request 'Remove nextjs scaffolding contents' (#113) from nextjs-scaffold-cleanup into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 27s
Playwright Tests / test (push) Successful in 2m39s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m43s
Reviewed-on: #113
2024-11-17 21:18:20 +00:00
5d39d49e5c Remove unused utils functions
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 36s
Add copyright notice / copyright_notice (pull_request) Successful in 54s
Playwright Tests / test (pull_request) Successful in 2m15s
2024-11-17 22:16:00 +01:00
161a27160f Remove nextjs scaffolding contents
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m30s
Playwright Tests / test (pull_request) Failing after 1m39s
Add copyright notice / copyright_notice (pull_request) Successful in 1m59s
2024-11-17 20:05:10 +01:00
827271efc2 Simplify guest edition by adding status to the dialog
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 43s
Add copyright notice / copyright_notice (pull_request) Successful in 54s
Playwright Tests / test (pull_request) Failing after 3m23s
2024-11-17 19:49:39 +01:00
6906b3cb6e Merge pull request 'Remove component that renders groups in a tree structure' (#111) from cleanup-tree-hierarchy into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 49s
Playwright Tests / test (push) Successful in 3m23s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m29s
Reviewed-on: #111
2024-11-17 18:27:47 +00:00
f424ec6654 Merge pull request 'Reuse the guest creation dialog for the editing flow' (#110) from edition-dialog into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 2m15s
Build Nginx-based docker image / build-static-assets (push) Failing after 4m6s
Playwright Tests / test (push) Has been cancelled
Reviewed-on: #110
2024-11-17 18:22:38 +00:00
ec49fd01e7 Remove component that renders groups in a tree structure
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m39s
Add copyright notice / copyright_notice (pull_request) Successful in 2m21s
Playwright Tests / test (pull_request) Successful in 5m0s
2024-11-17 19:22:30 +01:00
2955155778 Temporarily remove test to update guest name
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 31s
Add copyright notice / copyright_notice (pull_request) Successful in 1m0s
Playwright Tests / test (pull_request) Successful in 2m18s
2024-11-17 19:19:22 +01:00
52caefc220 Reuse the same dialog for creating and editing guests 2024-11-17 19:18:20 +01:00
51f7f96ee8 Merge pull request 'Allow removing a guest' (#109) from delete-guests into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m26s
Playwright Tests / test (push) Successful in 3m30s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m34s
Reviewed-on: #109
2024-11-17 17:33:59 +00:00
6e598e537b Allow removing a guest
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m43s
Add copyright notice / copyright_notice (pull_request) Successful in 2m24s
Playwright Tests / test (pull_request) Successful in 3m54s
2024-11-17 18:29:50 +01:00
318d203fed Merge pull request 'Extract APIs to their own files' (#108) from extract-apis into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 40s
Playwright Tests / test (push) Successful in 2m49s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m20s
Reviewed-on: #108
2024-11-17 17:02:08 +00:00
c1d199f08d Remove extension from the API's URLs
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 39s
Add copyright notice / copyright_notice (pull_request) Successful in 51s
Playwright Tests / test (pull_request) Successful in 2m47s
2024-11-17 17:58:08 +01:00
1fdac88c75 Fix race condition updating guests
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 44s
Add copyright notice / copyright_notice (pull_request) Successful in 59s
Playwright Tests / test (pull_request) Failing after 3m42s
2024-11-17 17:50:06 +01:00
01bce277a8 Add copyright notice
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 52s
Add copyright notice / copyright_notice (pull_request) Successful in 1m56s
Playwright Tests / test (pull_request) Failing after 6m24s
2024-11-17 16:07:50 +00:00
671bfce34f Refactor guests API 2024-11-17 16:07:50 +00:00
28abb23a77 Extract a table simulations API 2024-11-17 16:07:50 +00:00
92d929c8e1 Extract expenses API 2024-11-17 16:07:50 +00:00
53c4938e92 Extract groups API 2024-11-17 16:07:50 +00:00
470366b8f6 Extract a guests API 2024-11-17 16:07:50 +00:00
c6d30a101f Merge pull request 'Define a dialog to create a new guest' (#107) from new-guest into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 55s
Build Nginx-based docker image / build-static-assets (push) Failing after 3m34s
Playwright Tests / test (push) Successful in 3m44s
Reviewed-on: #107
2024-11-17 15:17:55 +00:00
3cca58cfb0 Define a dialog to create a new guest
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m53s
Playwright Tests / test (pull_request) Successful in 3m47s
Add copyright notice / copyright_notice (pull_request) Successful in 58s
2024-11-17 16:10:01 +01:00
71d9a91d18 Merge pull request 'Adapt the guests table to use the new API format' (#105) from guests-api-changes into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m46s
Playwright Tests / test (push) Successful in 3m44s
Build Nginx-based docker image / build-static-assets (push) Successful in 9m17s
Reviewed-on: #105
2024-11-17 10:43:37 +00:00
7b62992a5f Fix lowercase issues in API mocks for playwright
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m42s
Add copyright notice / copyright_notice (pull_request) Successful in 2m4s
Playwright Tests / test (pull_request) Successful in 3m35s
2024-11-17 11:39:56 +01:00
760bb016fb Merge branch 'main' into guests-api-changes
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m1s
Add copyright notice / copyright_notice (pull_request) Successful in 3m14s
Playwright Tests / test (pull_request) Failing after 8m1s
2024-11-16 08:51:57 +00:00
Renovate Bot
3231d5caa8 Update pnpm to v9.13.2
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 8m38s
Add copyright notice / copyright_notice (pull_request) Successful in 12m43s
Playwright Tests / test (pull_request) Successful in 23m50s
Check usage of free licenses / build-static-assets (push) Successful in 4m11s
Playwright Tests / test (push) Successful in 11m3s
Build Nginx-based docker image / build-static-assets (push) Successful in 22m17s
2024-11-16 01:09:33 +00:00
6fcf7d87a8 Adapt guest spec tests to the new API format
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 57s
Add copyright notice / copyright_notice (pull_request) Successful in 1m23s
Playwright Tests / test (pull_request) Failing after 22m0s
2024-11-16 00:49:40 +01:00
567ce207cf Adapt the guests table to use the new API format
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 34s
Add copyright notice / copyright_notice (pull_request) Successful in 39s
Playwright Tests / test (pull_request) Failing after 4m43s
2024-11-16 00:45:45 +01:00
Renovate Bot
03f2d87b6e Update pnpm to v9.13.1
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 3m12s
Playwright Tests / test (push) Successful in 5m1s
Build Nginx-based docker image / build-static-assets (push) Successful in 8m11s
2024-11-15 07:35:08 +00:00
Renovate Bot
c08e95e3b7 Update dependency tailwindcss to v3.4.15
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m56s
Add copyright notice / copyright_notice (pull_request) Successful in 7m27s
Playwright Tests / test (pull_request) Successful in 4m14s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
2024-11-15 01:09:09 +00:00
Renovate Bot
aa68e19ba0 Update pnpm to v9.13.0
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m46s
Playwright Tests / test (pull_request) Successful in 4m34s
Add copyright notice / copyright_notice (pull_request) Successful in 24s
Check usage of free licenses / build-static-assets (push) Successful in 1m40s
Playwright Tests / test (push) Successful in 6m15s
Build Nginx-based docker image / build-static-assets (push) Successful in 9m39s
2024-11-14 01:08:12 +00:00
09fa6002d9 Merge pull request 'Test the display of groups' (#101) from playwright-display-groups into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 53s
Playwright Tests / test (push) Successful in 2m23s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m53s
Reviewed-on: #101
2024-11-13 23:39:47 +00:00
a7c59f3f0f Test the display of groups
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 43s
Add copyright notice / copyright_notice (pull_request) Successful in 53s
Playwright Tests / test (pull_request) Successful in 2m5s
2024-11-14 00:34:15 +01:00
be7aed8246 Merge pull request 'Include playwright test for changing guest name' (#100) from playwright-guests-change-name into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m1s
Playwright Tests / test (push) Successful in 2m48s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m16s
Reviewed-on: #100
2024-11-13 23:28:16 +00:00
a4815c6f14 Include playwright test for changing guest name
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m27s
Add copyright notice / copyright_notice (pull_request) Successful in 2m4s
Playwright Tests / test (pull_request) Successful in 3m3s
2024-11-14 00:24:40 +01:00
3b8e7c9286 Merge pull request 'Improve Playwright tests of the guests page' (#99) from playwright-guests-page into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 54s
Playwright Tests / test (push) Successful in 2m31s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m28s
Reviewed-on: #99
2024-11-13 23:03:30 +00:00
321294c97d Improve Playwright tests of the guests page
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 36s
Add copyright notice / copyright_notice (pull_request) Successful in 47s
Playwright Tests / test (pull_request) Successful in 1m48s
2024-11-14 00:01:22 +01:00
4cf7c7eef1 Merge pull request 'Display a tab with information about groups' (#98) from groups-table into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m2s
Playwright Tests / test (push) Successful in 2m27s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m23s
Reviewed-on: #98
2024-11-13 18:29:15 +00:00
39907b0105 Fix tests
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 33s
Add copyright notice / copyright_notice (pull_request) Successful in 53s
Playwright Tests / test (pull_request) Successful in 2m16s
2024-11-13 19:26:51 +01:00
3e9775af99 Make color optional in a group
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m14s
Add copyright notice / copyright_notice (pull_request) Successful in 4m44s
Playwright Tests / test (pull_request) Failing after 9m9s
2024-11-13 08:58:55 +01:00
a6c517f8a1 Adjust styles of confirmed column 2024-11-13 08:47:50 +01:00
2985c8b73f Display a tab with information about groups
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 40s
Playwright Tests / test (pull_request) Failing after 58s
Add copyright notice / copyright_notice (pull_request) Successful in 1m1s
2024-11-13 08:16:10 +01:00
Renovate Bot
a8d01bcf88 Update dependency node to v23.2.0
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 3m36s
Playwright Tests / test (push) Successful in 24m32s
Build Nginx-based docker image / build-static-assets (push) Successful in 34m47s
2024-11-12 01:30:06 +00:00
Renovate Bot
3b0a3b25cd Update dependency postcss to v8.4.49
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m44s
Add copyright notice / copyright_notice (pull_request) Successful in 2m28s
Playwright Tests / test (pull_request) Successful in 7m20s
Check usage of free licenses / build-static-assets (push) Successful in 2m8s
Playwright Tests / test (push) Has been cancelled
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2024-11-12 01:08:24 +00:00
fd77360ec4 Merge pull request 'Allow inline editing of expenses' (#95) from inline-editing-expenses into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m31s
Playwright Tests / test (push) Successful in 4m41s
Build Nginx-based docker image / build-static-assets (push) Successful in 7m35s
Reviewed-on: #95
2024-11-11 07:28:00 +00:00
2d565e405f Allow inline editing of expenses
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m19s
Add copyright notice / copyright_notice (pull_request) Successful in 1m55s
Playwright Tests / test (pull_request) Successful in 5m26s
2024-11-11 07:14:34 +00:00
615106b42a Merge pull request 'Allow inline editing of guest name' (#94) from inline-edit-guests into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Failing after 48s
Playwright Tests / test (push) Failing after 48s
Build Nginx-based docker image / build-static-assets (push) Failing after 7m23s
Reviewed-on: #94
2024-11-11 07:14:24 +00:00
38ca2c3409 Allow inline editing of guest name
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m6s
Add copyright notice / copyright_notice (pull_request) Successful in 5m9s
Playwright Tests / test (pull_request) Successful in 8m52s
2024-11-11 08:01:45 +01:00
45a0da6b27 Merge pull request 'Implement expenses table and other changes' (#92) from expenses-table into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 1m18s
Playwright Tests / test (push) Successful in 7m10s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #92
2024-11-11 06:59:52 +00:00
Renovate Bot
0588459618 Update dependency postcss to v8.4.48
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m20s
Add copyright notice / copyright_notice (pull_request) Successful in 3m37s
Playwright Tests / test (pull_request) Successful in 6m48s
Check usage of free licenses / build-static-assets (push) Successful in 2m1s
Playwright Tests / test (push) Successful in 19m32s
Build Nginx-based docker image / build-static-assets (push) Failing after 19m45s
2024-11-11 01:07:31 +00:00
7434167583 Merge branch 'main' into expenses-table
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m42s
Playwright Tests / test (pull_request) Successful in 5m40s
Check usage of free licenses / build-static-assets (pull_request) Successful in 20s
2024-11-10 20:31:33 +00:00
10f7af1963 Merge pull request 'Extract a common TableOfContents component' (#91) from extract-table-component into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 2m34s
Playwright Tests / test (push) Failing after 3m9s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m37s
Reviewed-on: #91
2024-11-10 20:31:25 +00:00
7a0b03b67f Rename summary component and move it to the dashboard
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Failing after 17s
Add copyright notice / copyright_notice (pull_request) Failing after 18s
Playwright Tests / test (pull_request) Failing after 27s
2024-11-10 21:13:17 +01:00
638aca8301 Display a list of expenses
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 33s
Playwright Tests / test (pull_request) Failing after 55s
Check usage of free licenses / build-static-assets (pull_request) Failing after 1m3s
2024-11-10 21:08:03 +01:00
2ea1fd2667 Reuse the table of contents component for the guests list
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m13s
Add copyright notice / copyright_notice (pull_request) Successful in 2m28s
Playwright Tests / test (pull_request) Successful in 5m45s
2024-11-10 20:55:08 +01:00
79b4e9ac82 Add copyright notice
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Failing after 20s
Playwright Tests / test (pull_request) Failing after 54s
Add copyright notice / copyright_notice (pull_request) Failing after 16s
2024-11-10 19:53:34 +00:00
1838889a0c Extract a common TableOfContents component
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 30s
Add copyright notice / copyright_notice (pull_request) Successful in 44s
Playwright Tests / test (pull_request) Failing after 3m33s
2024-11-10 20:52:48 +01:00
Renovate Bot
f26e646a36 Update dependency next to v15.0.3
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 2m48s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m47s
Playwright Tests / test (pull_request) Successful in 17m22s
Check usage of free licenses / build-static-assets (push) Successful in 1m43s
Playwright Tests / test (push) Successful in 4m18s
Build Nginx-based docker image / build-static-assets (push) Successful in 7m38s
2024-11-08 01:10:09 +00:00
Renovate Bot
ea4ab9dc04 Update dependency @types/node to v22.9.0
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 3m34s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m27s
Playwright Tests / test (pull_request) Successful in 18m21s
Check usage of free licenses / build-static-assets (push) Successful in 5m51s
Playwright Tests / test (push) Successful in 17m53s
Build Nginx-based docker image / build-static-assets (push) Successful in 29m37s
2024-11-06 01:15:41 +00:00
e09a7a07af Merge pull request 'Update dependency @types/node to v22.8.7' (#87) from renovate/node-22.x into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 42s
Playwright Tests / test (push) Successful in 3m40s
Build Nginx-based docker image / build-static-assets (push) Successful in 5m1s
Reviewed-on: #87
2024-11-05 17:00:58 +00:00
Renovate Bot
f3862739c2 Update dependency @types/node to v22.8.7
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 27s
Check usage of free licenses / build-static-assets (pull_request) Successful in 36s
Playwright Tests / test (pull_request) Successful in 3m51s
2024-11-05 01:08:43 +00:00
c86018a24b Merge pull request 'Display the dish with the color of the group' (#86) from color-dishes into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Failing after 31s
Build Nginx-based docker image / build-static-assets (push) Failing after 31s
Playwright Tests / test (push) Failing after 32s
Reviewed-on: #86
2024-11-04 08:04:45 +00:00
5d537c80aa Display the dish with the color of the group
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m38s
Add copyright notice / copyright_notice (pull_request) Successful in 2m8s
Playwright Tests / test (pull_request) Successful in 5m27s
2024-11-03 14:42:06 +01:00
88d85c4f2c Merge pull request 'Prepare setup for development with Docker' (#85) from docker-compose-local-dev into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Failing after 17s
Playwright Tests / test (push) Failing after 17s
Build Nginx-based docker image / build-static-assets (push) Failing after 10m21s
Reviewed-on: #85
2024-11-03 13:19:53 +00:00
6109c2ce71 Prepare setup for development with Docker
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m19s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m1s
Playwright Tests / test (pull_request) Successful in 5m53s
2024-11-03 14:13:41 +01:00
919cd11915 Merge pull request 'Configure a build timeout of 30 minutes' (#81) from build-timeout into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 5m22s
Check usage of free licenses / build-static-assets (push) Successful in 6m59s
Playwright Tests / test (push) Failing after 8m44s
Reviewed-on: #81
2024-11-03 11:24:58 +00:00
15123351e1 Merge pull request 'Prevent redundant builds with copyright notice' (#80) from actions-concurrency into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 5m14s
Build Nginx-based docker image / build-static-assets (push) Failing after 12m8s
Playwright Tests / test (push) Successful in 15m54s
Reviewed-on: #80
2024-11-03 10:16:40 +00:00
a883b4b4bc Merge pull request 'Remove references to the user email' (#84) from remove-email into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 6m46s
Playwright Tests / test (push) Has been cancelled
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #84
2024-11-03 10:06:24 +00:00
7c0cd76198 Remove references to the user email
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 9m13s
Add copyright notice / copyright_notice (pull_request) Successful in 15m54s
Playwright Tests / test (pull_request) Successful in 11m26s
2024-11-03 10:39:02 +01:00
2fc13fbfa3 Merge pull request 'Fix error transitioning to the tentative status' (#83) from fix-transition-tentative-status into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 4m22s
Build Nginx-based docker image / build-static-assets (push) Failing after 14m24s
Playwright Tests / test (push) Successful in 17m35s
Reviewed-on: #83
2024-11-03 09:34:45 +00:00
0d1901fa44 Fix error transitioning to the tentative status
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 7m2s
Playwright Tests / test (pull_request) Successful in 22m52s
Add copyright notice / copyright_notice (pull_request) Failing after 2m45s
2024-11-03 10:34:30 +01:00
3b49064cb7 Merge branch 'main' into actions-concurrency
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m44s
Add copyright notice / copyright_notice (pull_request) Successful in 3m46s
Playwright Tests / test (pull_request) Successful in 12m11s
2024-11-03 09:15:48 +00:00
10e925c54f Configure a build timeout of 30 minutes
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m2s
Add copyright notice / copyright_notice (pull_request) Successful in 6m8s
Playwright Tests / test (pull_request) Successful in 12m33s
2024-11-03 09:15:21 +00:00
3b5d0918cd Merge pull request 'Stop building images on PRs' (#82) from build-main-only into main
Some checks are pending
Build Nginx-based docker image / build-static-assets (push) Waiting to run
Check usage of free licenses / build-static-assets (push) Successful in 2m58s
Playwright Tests / test (push) Successful in 11m20s
Reviewed-on: #82
2024-11-03 09:15:02 +00:00
e4dee0ded9 Stop building images on PRs
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 42s
Check usage of free licenses / build-static-assets (pull_request) Successful in 46s
Playwright Tests / test (pull_request) Successful in 7m9s
2024-11-03 10:07:41 +01:00
883c56e0e2 Prevent redundant builds with copyright notice
Some checks failed
Playwright Tests / test (pull_request) Failing after 14m40s
Check usage of free licenses / build-static-assets (pull_request) Failing after 15m29s
Build Nginx-based docker image / build-static-assets (pull_request) Failing after 57s
Add copyright notice / copyright_notice (pull_request) Failing after 15m14s
2024-11-03 09:32:04 +01:00
afd41cf9fe Merge pull request 'Display the name of the tables simulations' (#79) from arrangement-names into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m13s
Playwright Tests / test (push) Successful in 4m35s
Build Nginx-based docker image / build-static-assets (push) Successful in 9m15s
Reviewed-on: #79
2024-11-03 07:54:09 +00:00
81df69d78f Merge pull request 'Render rounded tables' (#78) from round-tables into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 1m56s
Playwright Tests / test (push) Successful in 4m56s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #78
2024-11-03 07:42:07 +00:00
78b0bd9755 Display the name of the tables simulations
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m48s
Add copyright notice / copyright_notice (pull_request) Successful in 2m17s
Playwright Tests / test (pull_request) Successful in 4m47s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 11m53s
2024-11-03 08:41:51 +01:00
efbc27a499 Render rounded tables
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m38s
Add copyright notice / copyright_notice (pull_request) Successful in 2m36s
Playwright Tests / test (pull_request) Successful in 5m27s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 7m21s
2024-11-03 08:20:47 +01:00
b36bb51fd7 Merge pull request 'table-component' (#75) from table-component into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m11s
Playwright Tests / test (push) Successful in 4m22s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m10s
Reviewed-on: #75
2024-11-02 12:03:51 +00:00
b5dd07c067 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m31s
Add copyright notice / copyright_notice (pull_request) Successful in 3m5s
Playwright Tests / test (pull_request) Successful in 6m49s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 9m50s
2024-11-02 11:53:56 +00:00
1b71bc9d79 Display the table arrangements returned by the API
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m21s
Add copyright notice / copyright_notice (pull_request) Successful in 1m53s
Playwright Tests / test (pull_request) Successful in 8m19s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 10m37s
2024-11-02 12:52:18 +01:00
ca353f02fe Code cleanup 2024-11-02 12:52:18 +01:00
58f9c35bf2 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m37s
Add copyright notice / copyright_notice (pull_request) Successful in 2m55s
Playwright Tests / test (pull_request) Successful in 4m44s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 6m38s
2024-11-02 10:26:40 +00:00
51d9a3d6e2 Render list of tables in an arrangement
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m40s
Add copyright notice / copyright_notice (pull_request) Successful in 2m1s
Playwright Tests / test (pull_request) Successful in 4m56s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 7m55s
2024-11-02 11:24:48 +01:00
094652d47e Mock tables of different sizes 2024-11-02 10:12:06 +01:00
de96b9d4ae Use a different color schema 2024-11-02 10:11:03 +01:00
Renovate Bot
aee7df4cf0 Update dependency node to v23.1.0
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 4m16s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 47m30s
Playwright Tests / test (pull_request) Successful in 32m58s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m19s
Check usage of free licenses / build-static-assets (push) Successful in 1m51s
Playwright Tests / test (push) Successful in 3m56s
Build Nginx-based docker image / build-static-assets (push) Successful in 6m4s
2024-11-02 01:08:05 +00:00
357fb617ce Add copyright notice
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m43s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m47s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 8m24s
Playwright Tests / test (pull_request) Successful in 2m55s
2024-11-01 17:27:41 +00:00
58b02839f2 Basic definition of a table component
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m10s
Add copyright notice / copyright_notice (pull_request) Successful in 1m34s
Playwright Tests / test (pull_request) Successful in 5m56s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 10m23s
2024-11-01 18:25:00 +01:00
a55b819378 Merge pull request 'Update node Docker tag to v23' (#57) from renovate/node-23.x into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 28s
Playwright Tests / test (push) Successful in 2m40s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m13s
Reviewed-on: #57
2024-11-01 10:33:36 +00:00
03a2f529c5 Upgrade to node 23
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 19s
Add copyright notice / copyright_notice (pull_request) Successful in 28s
Playwright Tests / test (pull_request) Successful in 2m39s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 2m57s
2024-11-01 11:30:31 +01:00
Renovate Bot
6ed88c5427 Update node Docker tag to v23 2024-11-01 11:28:42 +01:00
87b739aa89 Merge pull request 'Update dependency @types/react to v18.3.12' (#47) from renovate/react-18.x into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 53s
Playwright Tests / test (push) Successful in 2m46s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m8s
Reviewed-on: #47
2024-11-01 10:11:37 +00:00
dedffee536 Merge pull request 'Uninstall vercel/postgres dependency' (#73) from uninstall-vercel-postgres into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 48s
Playwright Tests / test (push) Has been cancelled
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #73
2024-11-01 10:07:44 +00:00
Renovate Bot
9c04dd604b Update dependency @types/react to v18.3.12
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m8s
Add copyright notice / copyright_notice (pull_request) Successful in 1m52s
Playwright Tests / test (pull_request) Successful in 4m25s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 6m33s
2024-11-01 11:04:43 +01:00
f8cea51c56 Uninstall vercel/postgres dependency
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 47s
Add copyright notice / copyright_notice (pull_request) Successful in 1m3s
Playwright Tests / test (pull_request) Successful in 3m7s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 5m28s
2024-11-01 11:00:35 +01:00
Renovate Bot
5154feb581 Update dependency @types/node to v22.8.6
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 52s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m21s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 14m22s
Playwright Tests / test (pull_request) Successful in 8m29s
Build Nginx-based docker image / build-static-assets (push) Successful in 7m41s
Check usage of free licenses / build-static-assets (push) Successful in 30s
Playwright Tests / test (push) Successful in 2m49s
2024-10-31 23:08:57 +00:00
266f0970a4 Merge pull request 'Define a dashboard summary mockup' (#71) from dashboard-summary into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 30s
Playwright Tests / test (push) Successful in 2m18s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m53s
Reviewed-on: #71
2024-10-31 07:25:50 +00:00
510b3140fd Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 43s
Add copyright notice / copyright_notice (pull_request) Successful in 1m12s
Playwright Tests / test (pull_request) Successful in 4m13s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 5m54s
2024-10-30 22:25:36 +00:00
d45ba871d8 Define a dashboard summary mockup
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 55s
Add copyright notice / copyright_notice (pull_request) Successful in 1m8s
Playwright Tests / test (pull_request) Successful in 3m41s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 6m43s
2024-10-30 23:24:29 +01:00
Renovate Bot
25a28e6065 Update dependency node to v22.11.0
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 2m9s
Playwright Tests / test (push) Successful in 4m27s
Build Nginx-based docker image / build-static-assets (push) Successful in 8m1s
2024-10-30 00:08:21 +00:00
Renovate Bot
4a9bf30886 Update dependency next to v15.0.2
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 1m1s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m6s
Playwright Tests / test (pull_request) Successful in 9m25s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 15m57s
Check usage of free licenses / build-static-assets (push) Successful in 2m7s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
2024-10-29 23:05:30 +00:00
Renovate Bot
9e8a35ad81 Update dependency @types/node to v22.8.2
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m26s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 27m35s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m50s
Playwright Tests / test (pull_request) Successful in 6m0s
Check usage of free licenses / build-static-assets (push) Successful in 1m20s
Playwright Tests / test (push) Successful in 8m33s
Build Nginx-based docker image / build-static-assets (push) Successful in 16m14s
2024-10-28 23:07:17 +00:00
a96ad3692e Merge pull request 'Add .ts extension to copyright notice' (#67) from copyright-v2 into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 28s
Playwright Tests / test (push) Successful in 2m45s
Build Nginx-based docker image / build-static-assets (push) Successful in 3m39s
Reviewed-on: #67
2024-10-28 08:03:35 +00:00
Renovate Bot
69b0f165fa Update dependency @types/node to v22.8.1
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m16s
Playwright Tests / test (push) Successful in 6m57s
Build Nginx-based docker image / build-static-assets (push) Successful in 18m24s
2024-10-27 23:27:32 +00:00
Renovate Bot
f85d4eecb6 Update dependency @playwright/test to v1.48.2
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m17s
Add copyright notice / copyright_notice (pull_request) Successful in 1m33s
Playwright Tests / test (pull_request) Successful in 3m44s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 10m43s
Playwright Tests / test (push) Waiting to run
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
2024-10-27 23:05:56 +00:00
18a0fdc514 Add copyright notice
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 3m40s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m17s
Playwright Tests / test (pull_request) Successful in 6m11s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 18m2s
2024-10-27 21:27:41 +00:00
ca17dd1adb Add .ts extension to copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m28s
Add copyright notice / copyright_notice (pull_request) Successful in 2m49s
Playwright Tests / test (pull_request) Successful in 6m23s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 16m5s
2024-10-27 22:24:55 +01:00
25703098d1 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m47s
Add copyright notice / copyright_notice (pull_request) Successful in 3m4s
Playwright Tests / test (pull_request) Successful in 6m8s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 11m35s
Check usage of free licenses / build-static-assets (push) Successful in 1m34s
Playwright Tests / test (push) Successful in 4m30s
Build Nginx-based docker image / build-static-assets (push) Successful in 17m58s
2024-10-27 21:11:45 +00:00
58a432ed6c Use a custom PAT instead of the GITHUB_TOKEN default
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m7s
Add copyright notice / copyright_notice (pull_request) Successful in 2m26s
Playwright Tests / test (pull_request) Successful in 5m26s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 13m28s
2024-10-27 22:09:27 +01:00
02817de72a Push only when there are changes 2024-10-27 22:09:02 +01:00
9fe306004b Fix extension
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m47s
Add copyright notice / copyright_notice (pull_request) Successful in 2m31s
Build Nginx-based docker image / build-static-assets (pull_request) Failing after 5m52s
Playwright Tests / test (pull_request) Successful in 5m3s
2024-10-27 22:02:14 +01:00
1a44ecd8e6 Add debug message to check if there are changes
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m30s
Add copyright notice / copyright_notice (pull_request) Failing after 2m39s
Playwright Tests / test (pull_request) Successful in 4m57s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 11m5s
2024-10-27 21:59:23 +01:00
14b527f8b4 Add notice only for rb files
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m30s
Add copyright notice / copyright_notice (pull_request) Failing after 2m29s
Playwright Tests / test (pull_request) Successful in 5m51s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 7m40s
2024-10-27 21:50:32 +01:00
f85d800127 Attempt to push with an explicit ref
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m2s
Add copyright notice / copyright_notice (pull_request) Successful in 2m6s
Playwright Tests / test (pull_request) Successful in 4m22s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 10m40s
2024-10-27 21:46:37 +01:00
05bd1ac66c Fix branch name
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m44s
Add copyright notice / copyright_notice (pull_request) Failing after 1m57s
Playwright Tests / test (pull_request) Successful in 3m36s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 7m53s
2024-10-27 21:40:44 +01:00
f66f1eb0ca Merge remote-tracking branch 'origin/main' into license
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 3m19s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m26s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 10m26s
Playwright Tests / test (pull_request) Successful in 4m56s
2024-10-27 21:28:45 +01:00
c274ac0715 Fix tsx extension
Some checks failed
Playwright Tests / test (pull_request) Has been cancelled
Check usage of free licenses / build-static-assets (pull_request) Has been cancelled
Add copyright notice / copyright_notice (pull_request) Has been cancelled
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
2024-10-27 21:28:09 +01:00
ce90391564 Add action to include copyright notice
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m9s
Playwright Tests / test (pull_request) Has been cancelled
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
Add copyright notice / copyright_notice (pull_request) Has been cancelled
2024-10-27 21:26:40 +01:00
8eeab56eae Merge pull request 'Additional status changes' (#63) from additiona-status-changes into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 36s
Playwright Tests / test (push) Successful in 4m45s
Build Nginx-based docker image / build-static-assets (push) Successful in 13m34s
Reviewed-on: #63
2024-10-27 20:23:36 +00:00
c8977c0afa Add copyright notice action 2024-10-27 21:23:35 +01:00
def1daadc5 Merge branch 'main' into additiona-status-changes
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m48s
Playwright Tests / test (pull_request) Successful in 13m21s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 17m19s
2024-10-27 20:06:14 +00:00
d5bd5f2fdb Merge pull request 'Automatically cancel redundant builds' (#65) from concurrency-actions into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 1m54s
Playwright Tests / test (push) Successful in 4m52s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #65
2024-10-27 20:06:03 +00:00
5dc5f96a61 Automatically cancel redundant builds
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m19s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 28m45s
Playwright Tests / test (pull_request) Successful in 3m44s
2024-10-27 19:44:23 +01:00
9bc7f497cd Add transitions from the tentative status
Some checks failed
Playwright Tests / test (pull_request) Has been cancelled
Check usage of free licenses / build-static-assets (pull_request) Has been cancelled
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
2024-10-27 19:41:00 +01:00
63d07096bf Include transition to the transitive status
Some checks failed
Playwright Tests / test (pull_request) Has been cancelled
Check usage of free licenses / build-static-assets (pull_request) Has been cancelled
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
2024-10-27 19:37:24 +01:00
c1e40af2c4 Merge branch 'tentative-status' into additiona-status-changes 2024-10-27 19:34:42 +01:00
7fd8c9cd99 Flag tentative stsatus with a yellow icon
Some checks failed
Playwright Tests / test (pull_request) Has been cancelled
Check usage of free licenses / build-static-assets (pull_request) Has been cancelled
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
2024-10-27 19:28:43 +01:00
a4178038ad Merge pull request 'Feature: Mark guests as invited' (#60) from guest-status-changes into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 41s
Check usage of free licenses / build-static-assets (push) Successful in 2m22s
Playwright Tests / test (push) Has been cancelled
Reviewed-on: #60
2024-10-27 18:28:22 +00:00
60ad1d127d Include transitions to confirmed and declined
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m59s
Playwright Tests / test (pull_request) Successful in 8m48s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 14m59s
2024-10-27 19:24:21 +01:00
58c8f51510 Merge remote-tracking branch 'origin/main' into guest-status-changes
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m59s
Playwright Tests / test (pull_request) Successful in 10m17s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 11m49s
2024-10-27 19:07:39 +01:00
03b3a318c0 Refresh list of guests after status update
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m49s
Playwright Tests / test (pull_request) Successful in 8m48s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 17m41s
2024-10-27 19:05:46 +01:00
1d59535eb6 Submit status changes to the backend
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 34s
Playwright Tests / test (pull_request) Successful in 4m19s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 7m32s
2024-10-27 14:02:10 +01:00
8aef089a7e Avoid infinite loop loading the list of guests (#62)
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 30s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m17s
Playwright Tests / test (push) Successful in 3m1s
Reviewed-on: #62
Co-authored-by: Manuel Bustillo <bustikiller@bustikiller.com>
Co-committed-by: Manuel Bustillo <bustikiller@bustikiller.com>
2024-10-27 11:10:45 +00:00
45e2665997 Pass the ID of the guests that has just been invited
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 39s
Build Nginx-based docker image / build-static-assets (pull_request) Failing after 1m37s
Playwright Tests / test (pull_request) Successful in 3m56s
2024-10-27 12:05:35 +01:00
ae7b338771 Restructure the update payload 2024-10-27 11:58:48 +01:00
7ea96ea7ad Make patch request to the backend whenever a guest is invited 2024-10-27 11:56:04 +01:00
dde976b076 Create a button to invite guests 2024-10-27 11:53:45 +01:00
63d4420806 Restore usage of client component and remove explicit async
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 22s
Playwright Tests / test (pull_request) Successful in 2m37s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 4m29s
2024-10-27 11:52:42 +01:00
de595bbf51 Avoid infinite loop by marking the component as server-side
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 25s
Playwright Tests / test (pull_request) Successful in 2m39s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 4m9s
2024-10-27 11:37:27 +01:00
7c6f00155a Merge pull request 'Define a gitea action to prevent the inclusion of nonfree dependencies' (#61) from license-finder into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 58s
Playwright Tests / test (push) Successful in 3m22s
Build Nginx-based docker image / build-static-assets (push) Successful in 4m39s
Reviewed-on: #61
2024-10-27 10:17:24 +00:00
924922c425 Define a gitea action to prevent the inclusion of nonfree dependencies
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m19s
Playwright Tests / test (pull_request) Successful in 3m27s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 6m26s
2024-10-27 11:10:49 +01:00
Renovate Bot
5230b96983 Update dependency next to v15.0.1
Some checks failed
Playwright Tests / test (pull_request) Successful in 7m23s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 15m43s
Playwright Tests / test (push) Failing after 4m57s
Build Nginx-based docker image / build-static-assets (push) Failing after 10m0s
2024-10-25 22:14:27 +00:00
Renovate Bot
7cbd683857 Update dependency node to v22.10.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 8m40s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 16m8s
Playwright Tests / test (push) Successful in 5m4s
Build Nginx-based docker image / build-static-assets (push) Successful in 12m11s
2024-10-24 22:10:17 +00:00
Renovate Bot
a74a15bdb6 Update dependency @playwright/test to v1.48.1
All checks were successful
Playwright Tests / test (pull_request) Successful in 7m52s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 23m14s
Playwright Tests / test (push) Successful in 7m54s
Build Nginx-based docker image / build-static-assets (push) Successful in 11m10s
2024-10-23 22:10:21 +00:00
Renovate Bot
67a92722be Update dependency typescript to v5.6.3
All checks were successful
Playwright Tests / test (push) Successful in 8m26s
Build Nginx-based docker image / build-static-assets (push) Successful in 10m58s
2024-10-22 23:13:27 +00:00
Renovate Bot
dad56c029c Update dependency use-debounce to v10.0.4
Some checks failed
Playwright Tests / test (push) Has been cancelled
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2024-10-22 22:55:22 +00:00
Renovate Bot
0c83f96d20 Update dependency next-auth to v5.0.0-beta.25
Some checks are pending
Playwright Tests / test (pull_request) Successful in 4m40s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 9m20s
Build Nginx-based docker image / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
2024-10-22 22:08:52 +00:00
Renovate Bot
26f2ab63a2 Update dependency tailwindcss to v3.4.14
All checks were successful
Playwright Tests / test (push) Successful in 7m26s
Build Nginx-based docker image / build-static-assets (push) Successful in 15m56s
2024-10-21 23:42:09 +00:00
Renovate Bot
fb83e45508 Update dependency primereact to v10.8.4
Some checks are pending
Build Nginx-based docker image / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
2024-10-21 23:26:51 +00:00
Renovate Bot
b16e87e118 Update dependency next to v15.0.0
Some checks are pending
Build Nginx-based docker image / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
2024-10-21 23:20:25 +00:00
Renovate Bot
6d695bdb91 Update dependency @types/react-dom to v18.3.1
Some checks are pending
Playwright Tests / test (pull_request) Successful in 10m3s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 28m57s
Build Nginx-based docker image / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
2024-10-21 22:08:26 +00:00
ec81e8b38c Merge pull request 'Update dependency postcss to v8.4.47' (#41) from renovate/postcss-8.x into main
All checks were successful
Playwright Tests / test (push) Successful in 8m8s
Build Nginx-based docker image / build-static-assets (push) Successful in 10m58s
Reviewed-on: #41
2024-10-21 09:40:57 +00:00
1017e2c582 Merge pull request 'Update dependency @tailwindcss/forms to v0.5.9' (#43) from renovate/tailwindcss-forms-0.x-lockfile into main
Some checks failed
Playwright Tests / test (push) Waiting to run
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #43
2024-10-21 09:40:40 +00:00
Renovate Bot
977c39dc77 Update dependency @tailwindcss/forms to v0.5.9
All checks were successful
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 3m51s
Playwright Tests / test (pull_request) Successful in 2m2s
2024-10-16 22:06:14 +00:00
Renovate Bot
7fc5dd90db Update dependency postcss to v8.4.47
All checks were successful
Playwright Tests / test (pull_request) Successful in 3m37s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 16m37s
2024-09-20 20:14:57 +00:00
118a42fb31 Merge pull request 'Match image name with repo name' (#46) from refactor-registry into main
All checks were successful
Playwright Tests / test (push) Successful in 4m49s
Build Nginx-based docker image / build-static-assets (push) Successful in 8m47s
Reviewed-on: #46
2024-09-07 14:09:41 +00:00
bae33974b3 Match image name with repo name
All checks were successful
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 7m7s
Playwright Tests / test (pull_request) Successful in 10m6s
2024-09-07 15:57:06 +02:00
Renovate Bot
93df3e03bc Update dependency node to v22.8.0
Some checks failed
Playwright Tests / test (pull_request) Successful in 2m21s
Build docker image / build-static-assets (pull_request) Successful in 5m36s
Build docker image / build-static-assets (push) Failing after 1m25s
Playwright Tests / test (push) Successful in 4m5s
2024-09-04 22:06:48 +00:00
Renovate Bot
381f10145f Update dependency @types/node to v22.5.2
All checks were successful
Playwright Tests / test (pull_request) Successful in 2m5s
Build docker image / build-static-assets (pull_request) Successful in 5m46s
Playwright Tests / test (push) Successful in 1m44s
Build docker image / build-static-assets (push) Successful in 6m5s
2024-09-01 21:01:48 +00:00
Renovate Bot
ab7b2538ed Update dependency postcss to v8.4.43
All checks were successful
Build docker image / build-static-assets (pull_request) Successful in 2m29s
Playwright Tests / test (pull_request) Successful in 2m37s
Playwright Tests / test (push) Successful in 1m20s
Build docker image / build-static-assets (push) Successful in 3m5s
2024-09-01 20:02:03 +00:00
Renovate Bot
a6f71cece7 Update dependency postcss to v8.4.42
All checks were successful
Playwright Tests / test (pull_request) Successful in 1m57s
Build docker image / build-static-assets (pull_request) Successful in 2m53s
Build docker image / build-static-assets (push) Successful in 3m19s
Playwright Tests / test (push) Successful in 1m16s
2024-08-31 22:02:22 +00:00
7059b3e860 Merge pull request 'Update dependency @tailwindcss/forms to v0.5.8' (#36) from renovate/tailwindcss-forms-0.x-lockfile into main
All checks were successful
Playwright Tests / test (push) Successful in 1m4s
Build docker image / build-static-assets (push) Successful in 2m44s
Reviewed-on: #36
2024-08-31 08:43:11 +00:00
Renovate Bot
7a7cce1923 Update dependency @tailwindcss/forms to v0.5.8
All checks were successful
Playwright Tests / test (pull_request) Successful in 1m31s
Build docker image / build-static-assets (pull_request) Successful in 3m18s
2024-08-30 12:03:02 +00:00
Renovate Bot
59680c0ec2 Update dependency @types/react to v18.3.5
All checks were successful
Build docker image / build-static-assets (pull_request) Successful in 2m44s
Playwright Tests / test (push) Successful in 1m21s
Build docker image / build-static-assets (push) Successful in 3m9s
Playwright Tests / test (pull_request) Successful in 2m51s
2024-08-30 11:02:47 +00:00
Renovate Bot
863e3ced90 Update dependency @types/node to v22.5.1
All checks were successful
Playwright Tests / test (pull_request) Successful in 1m41s
Build docker image / build-static-assets (pull_request) Successful in 4m36s
Playwright Tests / test (push) Successful in 1m24s
Build docker image / build-static-assets (push) Successful in 3m41s
2024-08-28 01:05:49 +00:00
Renovate Bot
82f8169e1a Update dependency node to v22.7.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 1m32s
Build docker image / build-static-assets (pull_request) Successful in 2m47s
Playwright Tests / test (push) Successful in 1m19s
Build docker image / build-static-assets (push) Successful in 3m1s
2024-08-22 15:03:03 +00:00
Renovate Bot
8d4efbb0e5 Update dependency @types/node to v22.5.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 4m50s
Build docker image / build-static-assets (pull_request) Successful in 6m26s
Playwright Tests / test (push) Successful in 1m41s
Build docker image / build-static-assets (push) Successful in 3m22s
2024-08-21 17:03:45 +00:00
Renovate Bot
a6bc5e9ffa Update dependency @types/node to v22.4.2
All checks were successful
Playwright Tests / test (pull_request) Successful in 5m5s
Build docker image / build-static-assets (pull_request) Successful in 7m3s
Playwright Tests / test (push) Successful in 1m17s
Build docker image / build-static-assets (push) Successful in 2m59s
2024-08-21 02:02:48 +00:00
Renovate Bot
e37a5c90f4 Update dependency @types/react to v18.3.4
All checks were successful
Playwright Tests / test (pull_request) Successful in 5m26s
Build docker image / build-static-assets (pull_request) Successful in 8m10s
Playwright Tests / test (push) Successful in 2m13s
Build docker image / build-static-assets (push) Successful in 4m22s
2024-08-20 21:02:53 +00:00
Renovate Bot
50b4844bd5 Update dependency @types/node to v22.4.1
All checks were successful
Playwright Tests / test (pull_request) Successful in 1m34s
Build docker image / build-static-assets (pull_request) Successful in 4m46s
Playwright Tests / test (push) Successful in 1m38s
Build docker image / build-static-assets (push) Successful in 3m43s
2024-08-19 03:01:53 +00:00
138813b674 Merge pull request 'Display a table skeleton while the list of guests is loading' (#29) from skeleton into main
Some checks failed
Build docker image / build-static-assets (push) Failing after 1m15s
Playwright Tests / test (push) Successful in 3m11s
Reviewed-on: #29
2024-08-18 20:02:45 +00:00
61df349cee Capture error in case the connection is not OK
All checks were successful
Playwright Tests / test (pull_request) Successful in 2m20s
Build docker image / build-static-assets (pull_request) Successful in 3m56s
2024-08-18 20:01:17 +02:00
628ddc8eb2 Define table as a client component
Some checks failed
Playwright Tests / test (pull_request) Failing after 1m58s
Build docker image / build-static-assets (pull_request) Failing after 5m22s
2024-08-18 19:18:00 +02:00
4022928f1c Display a skeleton while guests information is loading
Some checks failed
Playwright Tests / test (pull_request) Failing after 1m12s
Build docker image / build-static-assets (pull_request) Failing after 4m27s
2024-08-18 18:41:44 +02:00
611b487db4 Define skeletons for the guests table (not working yet) 2024-08-18 18:09:09 +02:00
b7eb2838a0 Render table of guests as a server component 2024-08-18 17:46:37 +02:00
Renovate Bot
6bec29b665 Update dependency use-debounce to v10.0.3
All checks were successful
Playwright Tests / test (pull_request) Successful in 1m32s
Build docker image / build-static-assets (pull_request) Successful in 3m52s
Playwright Tests / test (push) Successful in 1m35s
Build docker image / build-static-assets (push) Successful in 6m43s
2024-08-17 11:05:05 +00:00
Renovate Bot
517599d7ae Update dependency @playwright/test to v1.46.1
All checks were successful
Build docker image / build-static-assets (pull_request) Successful in 2m12s
Playwright Tests / test (pull_request) Successful in 21m58s
Playwright Tests / test (push) Successful in 1m12s
Build docker image / build-static-assets (push) Successful in 2m53s
2024-08-16 21:04:33 +00:00
Renovate Bot
382ec2bf50 Update dependency @types/node to v22.4.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 2m57s
Build docker image / build-static-assets (pull_request) Successful in 4m44s
Playwright Tests / test (push) Successful in 1m46s
Build docker image / build-static-assets (push) Successful in 2m55s
2024-08-16 19:04:23 +00:00
Renovate Bot
0f73705963 Update dependency node to v22.6.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 4m50s
Build docker image / build-static-assets (pull_request) Successful in 14m19s
Playwright Tests / test (push) Successful in 3m19s
Build docker image / build-static-assets (push) Successful in 7m27s
2024-08-15 10:05:32 +00:00
f7ef7bea4e Merge pull request 'Configure .nvmrc file' (#24) from configure-nvmrc into main
All checks were successful
Playwright Tests / test (push) Successful in 2m48s
Build docker image / build-static-assets (push) Successful in 8m13s
Reviewed-on: #24
2024-08-15 09:40:31 +00:00
997f5ca156 Configure .nvmrc file
All checks were successful
Playwright Tests / test (pull_request) Successful in 5m33s
Build docker image / build-static-assets (pull_request) Successful in 10m4s
2024-08-15 10:59:19 +02:00
Renovate Bot
b80c536971 Update dependency @types/node to v22.3.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 4m25s
Build docker image / build-static-assets (pull_request) Successful in 8m18s
Playwright Tests / test (push) Successful in 2m26s
Build docker image / build-static-assets (push) Successful in 6m18s
2024-08-14 08:05:48 +00:00
Renovate Bot
8b0f62debd Update dependency tailwindcss to v3.4.10
All checks were successful
Playwright Tests / test (pull_request) Successful in 6m34s
Build docker image / build-static-assets (pull_request) Successful in 9m27s
Playwright Tests / test (push) Successful in 3m18s
Build docker image / build-static-assets (push) Successful in 8m0s
2024-08-13 21:04:33 +00:00
cf07e28510 Merge pull request 'Update docker/build-push-action action to v6' (#20) from renovate/docker-build-push-action-6.x into main
All checks were successful
Playwright Tests / test (push) Successful in 4m24s
Build docker image / build-static-assets (push) Successful in 17m48s
Reviewed-on: #20
2024-08-12 05:59:19 +00:00
fb0a465645 Merge pull request 'Update dependency @vercel/postgres to ^0.9.0' (#19) from renovate/vercel-postgres-0.x into main
Some checks failed
Build docker image / build-static-assets (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
Reviewed-on: #19
2024-08-12 05:59:05 +00:00
f928c9afdb Merge pull request 'Update node Docker tag to v22' (#21) from renovate/node-22.x into main
Some checks failed
Build docker image / build-static-assets (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
Reviewed-on: #21
2024-08-12 05:58:03 +00:00
Renovate Bot
0983249d4f Update node Docker tag to v22
All checks were successful
Playwright Tests / test (pull_request) Successful in 9m57s
Build docker image / build-static-assets (pull_request) Successful in 54m10s
2024-08-11 22:08:16 +00:00
Renovate Bot
c42a2580cd Update docker/build-push-action action to v6
All checks were successful
Playwright Tests / test (pull_request) Successful in 5m48s
Build docker image / build-static-assets (pull_request) Successful in 1h2m1s
2024-08-11 22:07:58 +00:00
Renovate Bot
97dc26e2ea Update dependency @vercel/postgres to ^0.9.0
All checks were successful
Playwright Tests / test (pull_request) Successful in 7m0s
Build docker image / build-static-assets (pull_request) Successful in 21m8s
2024-08-11 22:07:46 +00:00
Renovate Bot
f24dba1bd2 Update dependency use-debounce to v10.0.2
All checks were successful
Playwright Tests / test (push) Successful in 5m31s
Build docker image / build-static-assets (push) Successful in 41m31s
2024-08-11 22:05:30 +00:00
Renovate Bot
6e7a45c040 Update dependency typescript to v5.5.4
Some checks failed
Build docker image / build-static-assets (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
2024-08-11 21:57:03 +00:00
Renovate Bot
3266f1d346 Update dependency postcss to v8.4.41
Some checks failed
Build docker image / build-static-assets (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
2024-08-11 21:31:02 +00:00
Renovate Bot
81057df169 Update dependency next to v15.0.0-rc.0
Some checks are pending
Playwright Tests / test (pull_request) Successful in 6m59s
Build docker image / build-static-assets (pull_request) Successful in 22m54s
Build docker image / build-static-assets (push) Waiting to run
Playwright Tests / test (push) Waiting to run
2024-08-11 21:06:44 +00:00
2b49afc27c Merge pull request 'Configure docker build' (#17) from docker into main
All checks were successful
Playwright Tests / test (push) Successful in 5m54s
Build docker image / build-static-assets (push) Successful in 27m39s
Reviewed-on: #17
2024-08-11 20:58:20 +00:00
84 changed files with 3282 additions and 1971 deletions

13
.dockerignore Normal file
View File

@ -0,0 +1,13 @@
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode
.next
*.swp
/scripts

View File

@ -1,12 +1,13 @@
name: Build docker image
name: Build Nginx-based docker image
on:
push:
branches:
- main
pull_request:
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
build-static-assets:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
@ -14,18 +15,39 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
- name: Login to the private Docker registry
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
registry: ${{ secrets.PRIVATE_REGISTRY_HOST }}
username: ${{ secrets.PRIVATE_REGISTRY_USERNAME }}
password: ${{ secrets.PRIVATE_REGISTRY_TOKEN }}
- name: Build and push intermediate stages (deps)
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: bustikiller/wedding-planner-frontend:latest
cache-from: type=registry,ref=user/app:latest
target: deps
push: ${{ github.ref == 'refs/heads/main' }}
tags: ${{ secrets.PRIVATE_REGISTRY_HOST }}/${{ env.GITHUB_REPOSITORY }}:deps
cache-from: type=registry,ref=${{ secrets.PRIVATE_REGISTRY_HOST }}/${{ env.GITHUB_REPOSITORY }}:deps
cache-to: type=inline
- name: Build and push intermediate stages (builder)
uses: docker/build-push-action@v6
with:
context: .
target: builder
push: ${{ github.ref == 'refs/heads/main' }}
tags: ${{ secrets.PRIVATE_REGISTRY_HOST }}/${{ env.GITHUB_REPOSITORY }}:builder
cache-from: type=registry,ref=${{ secrets.PRIVATE_REGISTRY_HOST }}/${{ env.GITHUB_REPOSITORY }}:builder
cache-to: type=inline
- name: Build and push (final)
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.ref == 'refs/heads/main' }}
tags: ${{ secrets.PRIVATE_REGISTRY_HOST }}/${{ env.GITHUB_REPOSITORY }}:latest
cache-from: type=registry,ref=${{ secrets.PRIVATE_REGISTRY_HOST }}/${{ env.GITHUB_REPOSITORY }}:latest
cache-to: type=inline

35
.github/workflows/copyright_notice.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: Add copyright notice
on:
pull_request:
permissions:
contents: write
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
copyright_notice:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.ACTIONS_TOKEN }}
ref: ${{ github.head_ref }}
- uses: VinnyBabuManjaly/copyright-action@v1.0.0
with:
CopyrightString: '/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/\n\n'
FileType: '.tsx, .jsx, .ts'
Path: 'app/, config/, db/'
IgnorePath: 'testfolder1/a/, testfolder3'
- name: Commit changes
run: |
git config --local user.email "bustikiller@bustikiller.com"
git config --local user.name "Manuel Bustillo"
git add .
if [ -n "$(git status --porcelain)" ]; then
echo "there are changes";
git commit -m "Add copyright notice"
git push
else
echo "no changes";
fi

23
.github/workflows/license_finder.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Check usage of free licenses
on:
push:
branches:
- main
pull_request:
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
build-static-assets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
- name: Install license finder gem
run: gem install license_finder
- name: Run license finder
run: license_finder

View File

@ -4,8 +4,12 @@ on:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
test:
if: false
timeout-minutes: 60
runs-on: ubuntu-latest
container:

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
23.6.1

660
COPYING.md Normal file
View File

@ -0,0 +1,660 @@
# GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc.
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
## Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains
free software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing
under this license.
The precise terms and conditions for copying, distribution and
modification follow.
## TERMS AND CONDITIONS
### 0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public
License.
"Copyright" also means copyright-like laws that apply to other kinds
of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of
an exact copy. The resulting work is called a "modified version" of
the earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user
through a computer network, with no transfer of a copy, is not
conveying.
An interactive user interface displays "Appropriate Legal Notices" to
the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
### 1. Source Code.
The "source code" for a work means the preferred form of the work for
making modifications to it. "Object code" means any non-source form of
a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users can
regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same
work.
### 2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey,
without conditions so long as your license otherwise remains in force.
You may convey covered works to others for the sole purpose of having
them make modifications exclusively for you, or provide you with
facilities for running those works, provided that you comply with the
terms of this License in conveying all material for which you do not
control copyright. Those thus making or running the covered works for
you must do so exclusively on your behalf, under your direction and
control, on terms that prohibit them from making any copies of your
copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the
conditions stated below. Sublicensing is not allowed; section 10 makes
it unnecessary.
### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such
circumvention is effected by exercising rights under this License with
respect to the covered work, and you disclaim any intention to limit
operation or modification of the work as a means of enforcing, against
the work's users, your or third parties' legal rights to forbid
circumvention of technological measures.
### 4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
### 5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these
conditions:
- a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
- b) The work must carry prominent notices stating that it is
released under this License and any conditions added under
section 7. This requirement modifies the requirement in section 4
to "keep intact all notices".
- c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
- d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
### 6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of
sections 4 and 5, provided that you also convey the machine-readable
Corresponding Source under the terms of this License, in one of these
ways:
- a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
- b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the Corresponding
Source from a network server at no charge.
- c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
- d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
- e) Convey the object code using peer-to-peer transmission,
provided you inform other peers where the object code and
Corresponding Source of the work are being offered to the general
public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal,
family, or household purposes, or (2) anything designed or sold for
incorporation into a dwelling. In determining whether a product is a
consumer product, doubtful cases shall be resolved in favor of
coverage. For a particular product received by a particular user,
"normally used" refers to a typical or common use of that class of
product, regardless of the status of the particular user or of the way
in which the particular user actually uses, or expects or is expected
to use, the product. A product is a consumer product regardless of
whether the product has substantial commercial, industrial or
non-consumer uses, unless such uses represent the only significant
mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to
install and execute modified versions of a covered work in that User
Product from a modified version of its Corresponding Source. The
information must suffice to ensure that the continued functioning of
the modified object code is in no case prevented or interfered with
solely because modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or
updates for a work that has been modified or installed by the
recipient, or for the User Product in which it has been modified or
installed. Access to a network may be denied when the modification
itself materially and adversely affects the operation of the network
or violates the rules and protocols for communication across the
network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
### 7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders
of that material) supplement the terms of this License with terms:
- a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
- b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
- c) Prohibiting misrepresentation of the origin of that material,
or requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
- d) Limiting the use for publicity purposes of names of licensors
or authors of the material; or
- e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
- f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions
of it) with contractual assumptions of liability to the recipient,
for any liability that these contractual assumptions directly
impose on those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions; the
above requirements apply either way.
### 8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your license
from a particular copyright holder is reinstated (a) provisionally,
unless and until the copyright holder explicitly and finally
terminates your license, and (b) permanently, if the copyright holder
fails to notify you of the violation by some reasonable means prior to
60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
### 9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run
a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
### 10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
### 11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned
or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within the
scope of its coverage, prohibits the exercise of, or is conditioned on
the non-exercise of one or more of the rights that are specifically
granted under this License. You may not convey a covered work if you
are a party to an arrangement with a third party that is in the
business of distributing software, under which you make payment to the
third party based on the extent of your activity of conveying the
work, and under which the third party grants, to any of the parties
who would receive the covered work from you, a discriminatory patent
license (a) in connection with copies of the covered work conveyed by
you (or copies made from those copies), or (b) primarily for and in
connection with specific products or compilations that contain the
covered work, unless you entered into that arrangement, or that patent
license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
### 12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under
this License and any other pertinent obligations, then as a
consequence you may not convey it at all. For example, if you agree to
terms that obligate you to collect a royalty for further conveying
from those to whom you convey the Program, the only way you could
satisfy both those terms and this License would be to refrain entirely
from conveying the Program.
### 13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your
version supports such interaction) an opportunity to receive the
Corresponding Source of your version by providing access to the
Corresponding Source from a network server at no charge, through some
standard or customary means of facilitating copying of software. This
Corresponding Source shall include the Corresponding Source for any
work covered by version 3 of the GNU General Public License that is
incorporated pursuant to the following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
### 14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Affero General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever
published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions
of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
### 15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.
### 16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
### 17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
## How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively state
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper
mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for
the specific requirements.
You should also get your employer (if you work as a programmer) or
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. For more information on this, and how to apply and follow
the GNU AGPL, see <https://www.gnu.org/licenses/>.

View File

@ -1,6 +1,6 @@
# Based on https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
FROM node:20-alpine AS base
FROM node:23-alpine AS base
# Install dependencies only when needed
FROM base AS deps

28
Dockerfile.dev Normal file
View File

@ -0,0 +1,28 @@
# Based on https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
FROM node:23-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
COPY . /app/
ENV NODE_ENV development
ENV NEXT_TELEMETRY_DISABLED 1
EXPOSE 3000
ENV PORT=3000
CMD HOSTNAME="0.0.0.0" pnpm run dev

View File

@ -0,0 +1,45 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client'
import { AbstractApi } from '@/app/api/abstract-api';
import { Expense, ExpenseSerializer } from '@/app/lib/expense';
import { classNames } from '@/app/ui/components/button';
import ExpenseFormDialog from '@/app/ui/components/expense-form-dialog';
import ExpensesTable from '@/app/ui/expenses/table';
import SkeletonTable from '@/app/ui/guests/skeleton-row';
import { Suspense, useEffect, useState } from 'react';
export default function Page() {
const refreshExpenses = () => {
new AbstractApi<Expense>().getAll(new ExpenseSerializer(), (expenses: Expense[]) => {
setExpenses(expenses);
});
}
const [expenses, setExpenses] = useState<Expense[]>([]);
const [expenseBeingEdited, setExpenseBeingEdited] = useState<Expense | undefined>(undefined);
useEffect(() => { refreshExpenses() }, []);
return (
<div className="w-full">
<div className="flex flex-col w-full items-center justify-between">
<button onClick={() => setExpenseBeingEdited({})} className={classNames('primary')}>Add new</button>
<ExpenseFormDialog
key={expenseBeingEdited?.id}
onCreate={() => { refreshExpenses(); setExpenseBeingEdited(undefined) }}
expense={expenseBeingEdited}
visible={expenseBeingEdited !== undefined}
onHide={() => { setExpenseBeingEdited(undefined) }}
/>
<Suspense fallback={<SkeletonTable />}>
<ExpensesTable
expenses={expenses}
onUpdate={refreshExpenses}
onEdit={(expense) => setExpenseBeingEdited(expense)}
/>
</Suspense>
</div>
</div>
);
}

View File

@ -0,0 +1,119 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { AbstractApi, } from '@/app/api/abstract-api';
import { Group, GroupSerializer } from '@/app/lib/group';
import { Guest, GuestSerializer } from '@/app/lib/guest';
import { getCsrfToken, getSlug } from '@/app/lib/utils';
import AffinitiesFormDialog from '@/app/ui/components/affinities-form-dialog';
import { classNames } from '@/app/ui/components/button';
import GroupFormDialog from '@/app/ui/components/group-form-dialog';
import GuestFormDialog from '@/app/ui/components/guest-form-dialog';
import GroupsTable from '@/app/ui/groups/table';
import SkeletonTable from '@/app/ui/guests/skeleton-row';
import GuestsTable from '@/app/ui/guests/table';
import { TabPanel, TabView } from 'primereact/tabview';
import { Suspense, useState } from 'react';
export default function Page() {
function refreshGuests() {
new AbstractApi<Guest>().getAll(new GuestSerializer(), (objects: Guest[]) => {
setGuests(objects);
setGuestsLoaded(true);
});
}
function refreshGroups() {
new AbstractApi<Group>().getAll(new GroupSerializer(), (objects: Group[]) => {
setGroups(objects);
setGroupsLoaded(true);
});
}
function resetAffinities() {
fetch(`/api/${getSlug()}/groups/affinities/reset`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
}
})
}
const [groupsLoaded, setGroupsLoaded] = useState(false);
const [groups, setGroups] = useState<Array<Group>>([]);
const [groupBeingEdited, setGroupBeingEdited] = useState<Group | undefined>(undefined);
const [groupAffinitiesBeingEditted, setGroupAffinitiesBeingEditted] = useState<Group | undefined>(undefined);
const [guestsLoaded, setGuestsLoaded] = useState(false);
const [guests, setGuests] = useState<Array<Guest>>([]);
const [guestBeingEdited, setGuestBeingEdited] = useState<Guest | undefined>(undefined);
!groupsLoaded && refreshGroups();
!guestsLoaded && refreshGuests();
return (
<div className="w-full">
<TabView>
<TabPanel header="Guests" leftIcon="pi pi-users mx-2">
<div className="flex flex-col w-full items-center justify-between">
<button onClick={() => setGuestBeingEdited({})} className={classNames('primary')}>Add new</button>
<GuestFormDialog
key={guestBeingEdited?.id}
groups={groups}
onCreate={() => { refreshGuests(); setGuestBeingEdited(undefined) }}
guest={guestBeingEdited}
visible={guestBeingEdited !== undefined}
onHide={() => { setGuestBeingEdited(undefined) }}
/>
<Suspense fallback={<SkeletonTable />}>
<GuestsTable
guests={guests}
onUpdate={refreshGuests}
onEdit={(guest) => setGuestBeingEdited(guest)}
/>
</Suspense>
</div>
</ TabPanel>
<TabPanel header="Groups" leftIcon="pi pi-sitemap mx-2">
<div className="flex flex-col w-full items-center justify-between">
<div>
<button onClick={() => setGroupBeingEdited({})} className={classNames('primary')}>Add new</button>
<button onClick={resetAffinities} className={classNames('yellow')}>Reset affinities</button>
</div>
<GroupFormDialog
key={groupBeingEdited?.id}
groups={groups}
onCreate={() => { refreshGroups(); setGroupBeingEdited(undefined) }}
group={groupBeingEdited}
visible={groupBeingEdited !== undefined}
onHide={() => { setGroupBeingEdited(undefined) }}
/>
<AffinitiesFormDialog
groups={groups}
group={groupAffinitiesBeingEditted}
visible={groupAffinitiesBeingEditted !== undefined}
onHide={() => { setGroupAffinitiesBeingEditted(undefined) }}
/>
<Suspense fallback={<SkeletonTable />}>
<GroupsTable
groups={groups}
onUpdate={refreshGroups}
onEdit={(group) => setGroupBeingEdited(group)}
onEditAffinities={(group) => setGroupAffinitiesBeingEditted(group)}
/>
</Suspense>
</div>
</ TabPanel>
</ TabView>
</div>
);
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import SideNav from '@/app/ui/dashboard/sidenav';
export default function Layout({ children }: { children: React.ReactNode }) {
@ -6,7 +8,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
<div className="w-full flex-none md:w-64">
<SideNav />
</div>
<div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
<div data-testid="main-container" className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
</div>
);
}

View File

@ -0,0 +1,26 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client'
import { GlobalSummary as Summary } from '@/app/lib/definitions';
import { getSlug } from '@/app/lib/utils';
import GlobalSummary from '@/app/ui/dashboard/global-summary';
import { useEffect, useState } from 'react';
export default function Page() {
const [globalSummary, setGlobalSummary] = useState<Summary | undefined>(undefined);
function refreshSummary() {
fetch(`/api/${getSlug()}/summary`)
.then((response) => response.json())
.then((data) => {
setGlobalSummary(data);
})
}
useEffect(refreshSummary, []);
return (
globalSummary && <GlobalSummary summary={globalSummary} />
);
}

View File

@ -0,0 +1,18 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import Arrangement from '@/app/ui/arrangements/arrangement';
import React, { useState } from 'react';
import ArrangementsTable from '@/app/ui/arrangements/arrangements-table';
export default function Page() {
const [currentArrangement, setCurrentArrangement] = useState<string | null>(null);
return (
<>
<ArrangementsTable onArrangementSelected={setCurrentArrangement} />
{currentArrangement && <Arrangement key={currentArrangement} id={currentArrangement} />}
</>
)
}

40
app/[slug]/page.tsx Normal file
View File

@ -0,0 +1,40 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import LoginForm from '@/app/ui/components/login-form';
import RegistrationForm from '@/app/ui/components/registration-form';
import { useParams } from 'next/navigation'
import { useEffect } from 'react';
import { retrieveCSRFToken } from '../api/authentication';
import { getCsrfToken } from '../lib/utils';
export default async function Page() {
const params = useParams<{ slug: string }>()
useEffect(() => {
if (getCsrfToken() == 'unknown') {
retrieveCSRFToken();
}
}, []);
if (typeof window !== 'undefined') {
localStorage.setItem('slug', await params.slug);
}
return (
<main className="flex min-h-screen flex-col p-6">
<div className="flex flex-row">
<div className="w-1/2">
Already have an account? Sign in
<LoginForm />
</div>
<div className="w-1/2">
Don't have an account? Register now!
<RegistrationForm />
</div>
</div>
</main>
);
}

76
app/api/abstract-api.tsx Normal file
View File

@ -0,0 +1,76 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Entity } from '@/app/lib/definitions';
import { getCsrfToken, getSlug } from '@/app/lib/utils';
export interface Api<T extends Entity> {
getAll(serializable: Serializable<T> ,callback: (objets: T[]) => void): void;
get(serializable: Serializable<T>, id: string, callback: (object: T) => void): void;
create(serializable: Serializable<T>, object: T, callback: () => void): void;
update(serializable: Serializable<T>, object: T, callback: () => void): void;
destroy(serializable: Serializable<T>, object: T, callback: () => void): void;
}
export interface Serializable<T> {
fromJson(json: any): T;
toJson(object: T): string;
apiPath(): string;
}
export class AbstractApi<T extends Entity> implements Api<T> {
getAll(serializable: Serializable<T>, callback: (objets: T[]) => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}`)
.then((response) => response.json())
.then((data) => {
callback(data.map((record: any) => {
return serializable.fromJson(record);
}));
}, (error) => {
return [];
});
}
get(serializable: Serializable<T>, id: string, callback: (object: T) => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}/${id}`)
.then((response) => response.json())
.then((data) => {
callback(serializable.fromJson(data));
}, (error) => {
return [];
});
}
update(serializable: Serializable<T>, object: T, callback: () => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, {
method: 'PUT',
body: serializable.toJson(object),
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
}
}).then(callback)
.catch((error) => console.error(error));
}
create(serializable: Serializable<T>, object: T, callback: () => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}`, {
method: 'POST',
body: serializable.toJson(object),
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
}
}).then(callback)
.catch((error) => console.error(error));
}
destroy(serializable: Serializable<T>, object: T, callback: () => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': getCsrfToken(),
}
}).then(callback)
.catch((error) => console.error(error));
}
}

View File

@ -0,0 +1,86 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { asArray, getCsrfToken, getSlug } from '@/app/lib/utils';
import { Captcha, StructuredErrors, User } from '@/app/lib/definitions';
export function login({ email, password, onLogin }: { email: string, password: string, onLogin: (user: User) => void }) {
return fetch(`/api/${getSlug()}/users/sign_in`, {
method: 'POST',
body: JSON.stringify({ user: { email, password } }),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
}
})
.then((response) => response.json())
.then((data: any) => {
console.log(data);
onLogin({
id: data.id || '',
email: data.email || '',
});
})
.catch((error) => console.error(error));
}
export function logout({ onLogout }: { onLogout: () => void }) {
fetch(`/api/${getSlug()}/users/sign_out`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': getCsrfToken(),
}
}).then(onLogout)
.catch((error) => console.error(error));
}
function flattenErrors(errors: StructuredErrors): string[] {
if (errors instanceof Array) {
return errors;
}
return Object.keys(errors).map((key) => {
return `${key}: ${asArray(errors[key]).join(', ')}`;
});
}
// At this moment we're making an initial request to get a valid CSRF token
export function retrieveCSRFToken() {
return fetch(`/api/token`, {
headers: {
'Accept': 'application/json',
}
}).then((response) => { return null });
}
export function register({ slug, email, password, passwordConfirmation, captcha, onRegister, onError }: {
slug: string,
email: string,
password: string,
passwordConfirmation: string,
captcha: Captcha,
onRegister: () => void,
onError: (errors: string[]) => void
}) {
fetch(`/api/${slug}/users`, {
method: 'POST',
body: JSON.stringify(
{
user: { email, password, password_confirmation: passwordConfirmation },
captcha: { id: captcha.id, answer: captcha.answer }
}
),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
}
}).then((response) => {
if (response.ok) {
response.json().then(onRegister);
} else {
response.json().then((data: any) => {
onError(data.errors && flattenErrors(data.errors) || [data.error]);
});
}
})
}

19
app/api/captcha.tsx Normal file
View File

@ -0,0 +1,19 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { data } from "autoprefixer";
import { getCsrfToken } from "../lib/utils";
export function getCaptchaChallenge({onRetrieve}: {onRetrieve: (id: string, url: string) => void}){
return fetch('/api/captcha', {
method: 'POST',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
}
})
.then((response) => response.json())
.then((data: any) => {
onRetrieve(data.id, data.media_url)
})
.catch((error) => console.error(error));
}

7
app/api/health/route.ts Normal file
View File

@ -0,0 +1,7 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { NextResponse } from "next/server";
export function GET() {
return NextResponse.json({});
}

View File

@ -0,0 +1,20 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { TableArrangement } from '@/app/lib/definitions';
import { getSlug } from '../lib/utils';
export function loadTableSimulations(onLoad?: (tableSimulations: TableArrangement[]) => void) {
fetch(`/api/${getSlug()}/tables_arrangements`)
.then((response) => response.json())
.then((data) => {
onLoad && onLoad(data.map((record: any) => {
return ({
id: record.id,
name: record.name,
discomfort: record.discomfort,
});
}));
}, (error) => {
return [];
});
}

View File

@ -1,11 +0,0 @@
import { lusitana } from '@/app/ui/fonts';
export default function Page () {
return (
<div className="w-full">
<div className="flex w-full items-center justify-between">
<h1 className={`${lusitana.className} text-2xl`}>Expenses</h1>
</div>
</div>
);
}

View File

@ -1,20 +0,0 @@
import { lusitana } from '@/app/ui/fonts';
import AffinityGroupsTree from '@/app/ui/guests/affinity-groups-tree';
import GuestsTable from '@/app/ui/guests/table';
import { Tree } from 'primereact/tree';
import React, { useState, useEffect } from 'react';
export default function Page() {
return (
<div className="w-full">
<AffinityGroupsTree />
<h1 className={`${lusitana.className} text-2xl py-4`}>Guests</h1>
<div className="flex w-full items-center justify-between">
<GuestsTable />
</div>
</div>
);
}

View File

@ -1,3 +0,0 @@
export default function Page() {
return <p>Dashboard Page</p>;
}

View File

@ -1,11 +0,0 @@
import { lusitana } from '@/app/ui/fonts';
export default function Page () {
return (
<div className="w-full">
<div className="flex w-full items-center justify-between">
<h1 className={`${lusitana.className} text-2xl`}>Table distributions</h1>
</div>
</div>
);
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import '@/app/ui/global.css'
import 'primereact/resources/themes/lara-light-cyan/theme.css';

5
app/lib/affinities.tsx Normal file
View File

@ -0,0 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
export class Affinities {
[key:string]: number;
}

View File

@ -1,104 +1,49 @@
// This file contains type definitions for your data.
// It describes the shape of the data, and what data type each property should accept.
// For simplicity of teaching, we're manually defining these types.
// However, these types are generated automatically if you're using an ORM such as Prisma.
export type User = {
id: string;
name: string;
email: string;
password: string;
};
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
export type Customer = {
id: string;
name: string;
email: string;
image_url: string;
};
import { AttendanceSummary } from "./group";
import { Guest } from "./guest";
export type Guest = {
id: string;
name: string;
email: string;
group_name: string;
status: 'Considered' | 'Invited' | 'Confirmed' | 'Declined';
export interface Entity {
id?: string;
}
export type Group = {
export type TableArrangement = {
id: string;
number: number;
name: string;
guest_count: number;
icon: string;
children: Group[];
};
guests?: Guest[];
discomfort?: number
}
export type Invoice = {
export type User = {
id: string;
customer_id: string;
amount: number;
date: string;
// In TypeScript, this is called a string union type.
// It means that the "status" property can only be one of the two strings: 'pending' or 'paid'.
status: 'pending' | 'paid';
};
export type Revenue = {
month: string;
revenue: number;
};
export type LatestInvoice = {
id: string;
name: string;
image_url: string;
email: string;
amount: string;
};
}
// The database returns a number for amount, but we later format it to a string with the formatCurrency function
export type LatestInvoiceRaw = Omit<LatestInvoice, 'amount'> & {
amount: number;
};
export type guestsTable = {
export type Captcha = {
id: string;
customer_id: string;
name: string;
email: string;
image_url: string;
date: string;
amount: number;
status: 'pending' | 'paid';
answer: string;
}
export type StructuredErrors = {
[key: string]: string[] | string;
};
export type CustomersTableType = {
id: string;
name: string;
email: string;
image_url: string;
total_guests: number;
total_pending: number;
total_paid: number;
};
export type GlobalSummary = {
expenses: ExpenseSummary;
guests: AttendanceSummary
}
export type FormattedCustomersTable = {
id: string;
name: string;
email: string;
image_url: string;
total_guests: number;
total_pending: string;
total_paid: string;
};
export type ExpenseSummary = {
projected: ExpensePossibleSummary;
confirmed: ExpensePossibleSummary;
status: StatusSummary;
}
export type CustomerField = {
id: string;
name: string;
};
export type InvoiceForm = {
id: string;
customer_id: string;
amount: number;
status: 'pending' | 'paid';
};
export type ExpensePossibleSummary = {
total: number;
guests: number;
}
export type StatusSummary = {
paid: number;
}

41
app/lib/expense.tsx Normal file
View File

@ -0,0 +1,41 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Serializable } from "../api/abstract-api";
import { Entity } from "./definitions";
export const pricingTypes = ['fixed', 'per_person'] as const;
export type PricingType = typeof pricingTypes[number];
export class Expense implements Entity {
id?: string;
name?: string;
amount?: number;
pricingType?: PricingType;
constructor(id?: string, name?: string, amount?: number, pricingType?: PricingType) {
this.id = id;
this.name = name || '';
this.amount = amount || 0;
this.pricingType = pricingType || 'fixed';
}
}
export class ExpenseSerializer implements Serializable<Expense>{
fromJson(data: any): Expense {
return new Expense(data.id, data.name, data.amount, data.pricing_type);
}
toJson(expense: Expense): string {
return JSON.stringify({
expense: {
name: expense.name,
amount: expense.amount,
pricing_type: expense.pricingType
}
});
}
apiPath(): string {
return 'expenses';
}
}

64
app/lib/group.tsx Normal file
View File

@ -0,0 +1,64 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Entity } from "./definitions";
export type AttendanceSummary = {
considered: number;
invited: number;
confirmed: number;
declined: number;
tentative: number;
total: number;
}
export class Group implements Entity {
id?: string;
name?: string;
guest_count?: number;
icon?: string;
children?: Group[];
parentId?: string;
color?: string;
attendance?: AttendanceSummary
constructor(id?: string, name?: string, guest_count?: number, icon?: string, children?: Group[], parentId?: string, color?: string, attendance?: AttendanceSummary) {
this.id = id;
this.name = name;
this.guest_count = guest_count;
this.icon = icon;
this.children = children;
this.parentId = parentId;
this.color = color;
this.attendance = attendance;
}
}
export class GroupSerializer {
fromJson(data: any): Group {
return new Group(
data.id,
data.name,
data.guest_count,
data.icon,
data.children,
data.parent_id,
data.color,
data.attendance
);
}
toJson(group: Group): string {
return JSON.stringify({
group: {
name: group.name,
color: group.color,
icon: group.icon,
parent_id: group.parentId
}
});
}
apiPath(): string {
return 'groups';
}
}

42
app/lib/guest.tsx Normal file
View File

@ -0,0 +1,42 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Serializable } from "../api/abstract-api";
import { Entity } from "./definitions";
export const guestStatuses = ['considered', 'invited', 'confirmed', 'declined', 'tentative'] as const;
export type GuestStatus = typeof guestStatuses[number];
export class Guest implements Entity {
id?: string;
name?: string;
group_name?: string;
groupId?: string;
color?: string;
status?: GuestStatus;
children?: Guest[];
constructor(id?: string, name?: string, group_name?: string, groupId?: string, color?: string, status?: GuestStatus, children?: Guest[]) {
this.id = id;
this.name = name;
this.group_name = group_name;
this.groupId = groupId;
this.color = color;
this.status = status;
this.children = children;
}
}
export class GuestSerializer implements Serializable<Guest> {
fromJson(data: any): Guest {
return new Guest(data.id, data.name, data.group?.name, data.group?.id, data.color, data.status, data.children);
}
toJson(guest: Guest): string {
return JSON.stringify({ guest: { name: guest.name, status: guest.status, group_id: guest.groupId } });
}
apiPath(): string {
return 'guests';
}
}

View File

@ -1,147 +0,0 @@
// This file contains placeholder data that you'll be replacing with real data in the Data Fetching chapter:
// https://nextjs.org/learn/dashboard-app/fetching-data
const users = [
{
id: '410544b2-4001-4271-9855-fec4b6a6442a',
name: 'User',
email: 'user@nextmail.com',
password: '123456',
},
];
const customers = [
{
id: 'd6e15727-9fe1-4961-8c5b-ea44a9bd81aa',
name: 'Evil Rabbit',
email: 'evil@rabbit.com',
image_url: '/customers/evil-rabbit.png',
},
{
id: '3958dc9e-712f-4377-85e9-fec4b6a6442a',
name: 'Delba de Oliveira',
email: 'delba@oliveira.com',
image_url: '/customers/delba-de-oliveira.png',
},
{
id: '3958dc9e-742f-4377-85e9-fec4b6a6442a',
name: 'Lee Robinson',
email: 'lee@robinson.com',
image_url: '/customers/lee-robinson.png',
},
{
id: '76d65c26-f784-44a2-ac19-586678f7c2f2',
name: 'Michael Novotny',
email: 'michael@novotny.com',
image_url: '/customers/michael-novotny.png',
},
{
id: 'CC27C14A-0ACF-4F4A-A6C9-D45682C144B9',
name: 'Amy Burns',
email: 'amy@burns.com',
image_url: '/customers/amy-burns.png',
},
{
id: '13D07535-C59E-4157-A011-F8D2EF4E0CBB',
name: 'Balazs Orban',
email: 'balazs@orban.com',
image_url: '/customers/balazs-orban.png',
},
];
const guests = [
{
customer_id: customers[0].id,
amount: 15795,
status: 'pending',
date: '2022-12-06',
},
{
customer_id: customers[1].id,
amount: 20348,
status: 'pending',
date: '2022-11-14',
},
{
customer_id: customers[4].id,
amount: 3040,
status: 'paid',
date: '2022-10-29',
},
{
customer_id: customers[3].id,
amount: 44800,
status: 'paid',
date: '2023-09-10',
},
{
customer_id: customers[5].id,
amount: 34577,
status: 'pending',
date: '2023-08-05',
},
{
customer_id: customers[2].id,
amount: 54246,
status: 'pending',
date: '2023-07-16',
},
{
customer_id: customers[0].id,
amount: 666,
status: 'pending',
date: '2023-06-27',
},
{
customer_id: customers[3].id,
amount: 32545,
status: 'paid',
date: '2023-06-09',
},
{
customer_id: customers[4].id,
amount: 1250,
status: 'paid',
date: '2023-06-17',
},
{
customer_id: customers[5].id,
amount: 8546,
status: 'paid',
date: '2023-06-07',
},
{
customer_id: customers[1].id,
amount: 500,
status: 'paid',
date: '2023-08-19',
},
{
customer_id: customers[5].id,
amount: 8945,
status: 'paid',
date: '2023-06-03',
},
{
customer_id: customers[2].id,
amount: 1000,
status: 'paid',
date: '2022-06-05',
},
];
const revenue = [
{ month: 'Jan', revenue: 2000 },
{ month: 'Feb', revenue: 1800 },
{ month: 'Mar', revenue: 2200 },
{ month: 'Apr', revenue: 2500 },
{ month: 'May', revenue: 2300 },
{ month: 'Jun', revenue: 3200 },
{ month: 'Jul', revenue: 3500 },
{ month: 'Aug', revenue: 3700 },
{ month: 'Sep', revenue: 2500 },
{ month: 'Oct', revenue: 2800 },
{ month: 'Nov', revenue: 3000 },
{ month: 'Dec', revenue: 4800 },
];
export { users, customers, guests, revenue };

View File

@ -0,0 +1,71 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Serializable } from "../api/abstract-api";
import { Entity } from "./definitions";
import { Guest } from "./guest";
export type Discomfort = {
discomfort: number;
breakdown: {
tableSizePenalty: number;
cohesionPenalty: number;
}
}
export type Table = {
number: number;
guests: Guest[];
discomfort: Discomfort;
}
export class TableSimulation implements Entity {
id: string;
tables: Table[];
constructor(id: string, tables: Table[]) {
this.id = id;
this.tables = tables;
}
}
export class TableSimulationSerializer implements Serializable<TableSimulation> {
fromJson(data: any): TableSimulation {
return new TableSimulation(data.id, data.tables.map((table: any) => {
return {
number: table.number,
guests: table.guests.map((guest: any) => new Guest(guest.id, guest.name, guest.group?.name, guest.group?.id, guest.color)),
discomfort: {
discomfort: table.discomfort.discomfort,
breakdown: {
tableSizePenalty: table.discomfort.breakdown.table_size_penalty,
cohesionPenalty: table.discomfort.breakdown.cohesion_penalty,
}
},
}
}));
}
toJson(simulation: TableSimulation): string {
return JSON.stringify({ simulation: { tables: simulation.tables.map((table) => {
return {
number: table.number,
guests: table.guests.map((guest) => {
return {
id: guest.id,
name: guest.name,
group_id: guest.groupId,
color: guest.color,
status: guest.status,
children: guest.children,
}
}),
discomfort: table.discomfort,
}
}) } });
}
apiPath(): string {
return 'tables_arrangements';
}
}

View File

@ -1,69 +1,20 @@
import { Revenue } from './definitions';
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
export const formatCurrency = (amount: number) => {
return (amount / 100).toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
};
export const getCsrfToken = () => {
return document.cookie
.split("; ")
.find((row) => row.startsWith("csrf-token"))
?.split("=")[1] || 'unknown';
}
export const formatDateToLocal = (
dateStr: string,
locale: string = 'en-US',
) => {
const date = new Date(dateStr);
const options: Intl.DateTimeFormatOptions = {
day: 'numeric',
month: 'short',
year: 'numeric',
};
const formatter = new Intl.DateTimeFormat(locale, options);
return formatter.format(date);
};
export const getSlug = () => localStorage.getItem('slug') || 'default';
export const generateYAxis = (revenue: Revenue[]) => {
// Calculate what labels we need to display on the y-axis
// based on highest record and in 1000s
const yAxisLabels = [];
const highestRecord = Math.max(...revenue.map((month) => month.revenue));
const topLabel = Math.ceil(highestRecord / 1000) * 1000;
// From https://stackoverflow.com/a/1026087/3607039
export const capitalize = (val:string) => {
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
}
for (let i = topLabel; i >= 0; i -= 1000) {
yAxisLabels.push(`$${i / 1000}K`);
}
return { yAxisLabels, topLabel };
};
export const generatePagination = (currentPage: number, totalPages: number) => {
// If the total number of pages is 7 or less,
// display all pages without any ellipsis.
if (totalPages <= 7) {
return Array.from({ length: totalPages }, (_, i) => i + 1);
}
// If the current page is among the first 3 pages,
// show the first 3, an ellipsis, and the last 2 pages.
if (currentPage <= 3) {
return [1, 2, 3, '...', totalPages - 1, totalPages];
}
// If the current page is among the last 3 pages,
// show the first 2, an ellipsis, and the last 3 pages.
if (currentPage >= totalPages - 2) {
return [1, 2, '...', totalPages - 2, totalPages - 1, totalPages];
}
// If the current page is somewhere in the middle,
// show the first page, an ellipsis, the current page and its neighbors,
// another ellipsis, and the last page.
return [
1,
'...',
currentPage - 1,
currentPage,
currentPage + 1,
'...',
totalPages,
];
};
// From https://stackoverflow.com/a/62118163/3607039
export function asArray<T>(value: T | T[]): T[] {
return ([] as T[]).concat(value)
}

View File

@ -1,10 +0,0 @@
import Link from 'next/link';
import styles from '@/app/ui/home.module.css';
export default function Page() {
return (
<main className="flex min-h-screen flex-col p-6">
</main>
);
}

View File

@ -1,122 +0,0 @@
// import bcrypt from 'bcrypt';
// import { db } from '@vercel/postgres';
// import { guests, customers, revenue, users } from '../lib/placeholder-data';
// const client = await db.connect();
// async function seedUsers() {
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
// await client.sql`
// CREATE TABLE IF NOT EXISTS users (
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
// name VARCHAR(255) NOT NULL,
// email TEXT NOT NULL UNIQUE,
// password TEXT NOT NULL
// );
// `;
// const insertedUsers = await Promise.all(
// users.map(async (user) => {
// const hashedPassword = await bcrypt.hash(user.password, 10);
// return client.sql`
// INSERT INTO users (id, name, email, password)
// VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
// ON CONFLICT (id) DO NOTHING;
// `;
// }),
// );
// return insertedUsers;
// }
// async function seedguests() {
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
// await client.sql`
// CREATE TABLE IF NOT EXISTS guests (
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
// customer_id UUID NOT NULL,
// amount INT NOT NULL,
// status VARCHAR(255) NOT NULL,
// date DATE NOT NULL
// );
// `;
// const insertedguests = await Promise.all(
// guests.map(
// (invoice) => client.sql`
// INSERT INTO guests (customer_id, amount, status, date)
// VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
// ON CONFLICT (id) DO NOTHING;
// `,
// ),
// );
// return insertedguests;
// }
// async function seedCustomers() {
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
// await client.sql`
// CREATE TABLE IF NOT EXISTS customers (
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
// name VARCHAR(255) NOT NULL,
// email VARCHAR(255) NOT NULL,
// image_url VARCHAR(255) NOT NULL
// );
// `;
// const insertedCustomers = await Promise.all(
// customers.map(
// (customer) => client.sql`
// INSERT INTO customers (id, name, email, image_url)
// VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
// ON CONFLICT (id) DO NOTHING;
// `,
// ),
// );
// return insertedCustomers;
// }
// async function seedRevenue() {
// await client.sql`
// CREATE TABLE IF NOT EXISTS revenue (
// month VARCHAR(4) NOT NULL UNIQUE,
// revenue INT NOT NULL
// );
// `;
// const insertedRevenue = await Promise.all(
// revenue.map(
// (rev) => client.sql`
// INSERT INTO revenue (month, revenue)
// VALUES (${rev.month}, ${rev.revenue})
// ON CONFLICT (month) DO NOTHING;
// `,
// ),
// );
// return insertedRevenue;
// }
export async function GET() {
return Response.json({
message:
'Uncomment this file and remove this line. You can delete this file when you are finished.',
});
// try {
// await client.sql`BEGIN`;
// await seedUsers();
// await seedCustomers();
// await seedguests();
// await seedRevenue();
// await client.sql`COMMIT`;
// return Response.json({ message: 'Database seeded successfully' });
// } catch (error) {
// await client.sql`ROLLBACK`;
// return Response.json({ error }, { status: 500 });
// }
}

13
app/types.tsx Normal file
View File

@ -0,0 +1,13 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import * as HeroIcon from '@heroicons/react/24/outline'
import { ComponentProps } from 'react'
type Props = {
name: keyof typeof HeroIcon
} & ComponentProps<typeof HeroIcon.AcademicCapIcon>
export const Icon = ({ name, ...props }: Props) => {
const IconComponent = HeroIcon[name]
return <IconComponent {...props} />
}

View File

@ -0,0 +1,38 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { AbstractApi } from '@/app/api/abstract-api';
import { TableArrangement } from '@/app/lib/definitions';
import { TableSimulation, TableSimulationSerializer } from '@/app/lib/tableSimulation';
import { getSlug } from '@/app/lib/utils';
import { Table } from '@/app/ui/components/table';
import { lusitana } from '@/app/ui/fonts';
import { useState, useEffect } from 'react';
export default function Arrangement({ id }: { id: string }) {
const [simulation, setSimulation] = useState<TableSimulation | undefined>(undefined);
function loadSimulation() {
new AbstractApi<TableSimulation>().get(new TableSimulationSerializer(), id, (object: TableSimulation) => {
setSimulation(object);
});
}
useEffect(loadSimulation, []);
return (
<div className="w-full">
<div className="w-full items-center justify-between">
<h1 className={`${lusitana.className} text-2xl my-5`}>Table distributions</h1>
<div className="flex flex-row flex-wrap justify-around">
{simulation && simulation.tables.map((table) => (
<Table key={table.number} table={table} style="rounded" />
))}
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,48 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client'
import React, { useState } from "react"
import { TableArrangement } from '@/app/lib/definitions';
import { classNames } from "../components/button";
import TableOfContents from "../components/table-of-contents";
import { loadTableSimulations } from "@/app/api/tableSimulations";
export default function ArrangementsTable ({onArrangementSelected}: {onArrangementSelected: (arrangementId: string) => void}) {
const [arrangements, setArrangements] = useState<Array<TableArrangement>>([]);
const [arrangementsLoaded, setArrangementsLoaded] = useState(false);
function refreshSimulations() {
loadTableSimulations((arrangements) => {
setArrangements(arrangements);
setArrangementsLoaded(true);
});
}
function arrangementClicked(e: React.MouseEvent<HTMLElement>) {
onArrangementSelected(e.currentTarget.getAttribute('data-arrangement-id') || '');
}
!arrangementsLoaded && refreshSimulations();
return(
<TableOfContents
headers={['Name', 'Discomfort', 'Actions']}
caption='Simulations'
elements={arrangements}
rowRender={(arrangement) => (
<tr key={arrangement.id} className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800">
<th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{arrangement.name}
</th>
<td className="px-6 py-4">
{arrangement.discomfort}
</td>
<td>
<button data-arrangement-id={arrangement.id} onClick={arrangementClicked} className={classNames('primary')}>Load</button>
</td>
</tr>
)}
/>
);
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import clsx from 'clsx';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {

View File

@ -0,0 +1,82 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { Affinities } from '@/app/lib/affinities';
import { Group } from '@/app/lib/group';
import { getCsrfToken, getSlug } from '@/app/lib/utils';
import { classNames } from '@/app/ui/components/button';
import { Dialog } from 'primereact/dialog';
import { useEffect, useState } from 'react';
import AffinitySlider from './form/affinitySlider';
export default function AffinitiesFormDialog({ groups, group, visible, onHide }: {
groups: Group[],
group?: Group,
visible: boolean,
onHide: () => void,
}) {
const [affinities, setAffinities] = useState<Affinities>({});
const [isLoadingAffinities, setIsLoadingAffinities] = useState(true);
useEffect(() => {
setIsLoadingAffinities(true);
if (group?.id === undefined) {
setAffinities({});
setIsLoadingAffinities(false)
} else {
fetch(`/api/${getSlug()}/groups/${group?.id}/affinities`)
.then((response) => response.json())
.then((data) => {
setAffinities(data);
setIsLoadingAffinities(false)
});
}
}, [group]);
function submitAffinities() {
const formattedAffinities = Object.entries(affinities).map(([groupId, affinity]) => ({ group_id: groupId, affinity: affinity }));
fetch(`/api/${getSlug()}/groups/${group?.id}/affinities/bulk_update`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfToken(),
},
body: JSON.stringify({ affinities: formattedAffinities })
}).then(() => {
onHide();
});
}
function resetAffinities() {
fetch(`/api/${getSlug()}/groups/${group?.id}/affinities/default`, {
method: 'GET',
headers: {
'Accept': 'application/json',
}
}).then((response) => response.json())
.then(setAffinities);
}
return (
<Dialog header="Update affinities" visible={visible} style={{ width: '60vw' }} onHide={onHide}>
{!isLoadingAffinities && <div className="card justify-evenly py-5 bg-gray-200 flex flex-col">
<span className="text-center p-4">Describe the affinity with the rest of the groups</span>
{
groups.filter((currentGroup) => currentGroup.id !== group?.id).map((group) =>
<div key={group.id} className="flex flex-row hover:bg-gray-300 px-3 py-2 items-center">
<span className="w-1/3 text-right px-4">{group.name}</span>
<AffinitySlider value={group.id && affinities[group.id] || 1} onChange={(value) => setAffinities({ ...affinities, [group.id || "default"]: value })} />
</div>)
}
<div className="flex justify-center">
<button className={classNames('gray')} onClick={resetAffinities} >Reset</button>
<button className={classNames('primary')} onClick={submitAffinities} >Update</button>
</div>
</div>
}
</Dialog>
);
}

View File

@ -0,0 +1,15 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import clsx from "clsx";
type ButtonColor = 'primary' | 'blue' | 'green' | 'red' | 'yellow' | 'gray';
export function classNames(type: ButtonColor) {
return (clsx("text-white py-1 px-2 mx-1 rounded disabled:opacity-50 disabled:cursor-not-allowed", {
'bg-blue-400 hover:bg-blue-600': type === 'primary' || type === 'blue',
'bg-green-500 hover:bg-green-600': type === 'green',
'bg-red-500 hover:bg-red-600': type === 'red',
'bg-yellow-500 hover:bg-yellow-700': type === 'yellow',
'bg-gray-500 hover:bg-gray-700': type === 'gray'
}))
}

View File

@ -0,0 +1,53 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import clsx from "clsx"
import { Icon } from "../../types";
import * as HeroIcon from '@heroicons/react/24/outline'
type Style = "green" | "blue" | "red" | "orange" | "gray"
const colorClasses = (style: Style) => {
switch (style) {
case "green":
return "bg-green-700 hover:bg-green-800"
case "blue":
return "bg-blue-500 hover:bg-blue-700"
case "red":
return "bg-red-600 hover:bg-red-700"
case "orange":
return "bg-orange-600 hover:bg-orange-700"
case "gray":
return "bg-gray-600 hover:bg-gray-700"
}
}
export function MainCard({ amount, title, subtitle, style, iconName }:
{
amount: string,
title: string,
subtitle?: string,
style: Style,
iconName: keyof typeof HeroIcon
}) {
return (
<div className={`w-80 m-1 py-2 px-6 text-white flex flex-row items-center ${colorClasses(style)}`}>
<Icon className="m-3 h-14 w-14" name={iconName} />
<div className="flex flex-col justify-evenly">
<div className="text-4xl font-medium">{amount}</div>
<div className="text-xl">{title}</div>
<div className="text-sm">{subtitle || ''}</div>
</div>
</div>
);
}
export function SecondaryCard({ amount, title, iconName, style }: { amount: string, title: string, iconName: keyof typeof HeroIcon, style: Style }) {
return (
<div className={`h-12 w-80 m-1 p-2 text-white flex flex-row items-center ${colorClasses(style)}`}>
<Icon className="m-3 h-7 w-7" name={iconName} />
<span className="text-2xl font-medium mx-1">{amount}</span>
<span className="text-l mx-1">{title}</span>
</div>
);
}

View File

@ -0,0 +1,83 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { AbstractApi } from '@/app/api/abstract-api';
import { Expense, ExpenseSerializer, PricingType, pricingTypes } from '@/app/lib/expense';
import { capitalize } from '@/app/lib/utils';
import { classNames } from '@/app/ui/components/button';
import { Dialog } from 'primereact/dialog';
import { Dropdown } from 'primereact/dropdown';
import { FloatLabel } from 'primereact/floatlabel';
import { InputText } from 'primereact/inputtext';
import { useState } from 'react';
export default function ExpenseFormDialog({ onCreate, onHide, expense, visible }: {
onCreate?: () => void,
onHide: () => void,
expense?: Expense,
visible: boolean,
}) {
const [name, setName] = useState<string>(expense?.name || '');
const [amount, setAmount] = useState<number>(expense?.amount || 0);
const [pricingType, setPricingType] = useState<PricingType>(expense?.pricingType || 'fixed');
const api = new AbstractApi<Expense>();
const serializer = new ExpenseSerializer();
function resetForm() {
setName('');
setAmount(0);
setPricingType('fixed');
}
function submitGroup() {
if (expense?.id !== undefined) {
expense.name = name;
expense.amount = amount;
expense.pricingType = pricingType;
api.update(serializer, expense, () => {
resetForm();
onCreate && onCreate();
});
} else {
api.create(serializer, new Expense(undefined, name, amount, pricingType), () => {
resetForm();
onCreate && onCreate();
});
}
}
return (
<>
<Dialog header="Add/edit expense" visible={visible} style={{ width: '60vw' }} onHide={onHide}>
<div className="card flex justify-evenly py-5">
<FloatLabel>
<InputText id="name" className='rounded-sm' value={name} onChange={(e) => setName(e.target.value)} />
<label htmlFor="name">Name</label>
</FloatLabel>
<FloatLabel>
<InputText id="amount" className='rounded-sm' value={amount.toString()} onChange={(e) => setAmount(parseFloat(e.target.value))} />
<label htmlFor="amount">Amount</label>
</FloatLabel>
<FloatLabel>
<Dropdown id="pricingType" className='rounded-sm min-w-32' value={pricingType} onChange={(e) => setPricingType(e.target.value)} options={
pricingTypes.map((type) => {
return { label: capitalize(type), value: type };
})
} />
<label htmlFor="pricingType">Pricing type</label>
</FloatLabel>
<button className={classNames('primary')} onClick={submitGroup} disabled={!(name.length > 0)}>
{expense?.id !== undefined ? 'Update' : 'Create'}
</button>
</div>
</Dialog>
</>
);
}

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Slider } from 'primereact/slider';
export default function AffinitySlider({ value, onChange }: { value: number, onChange: (value: number) => void }) {
const toNumber = (value : number | [number, number]) => {
if(value instanceof Array) {
return value[0];
}
return value;
}
const label = (value: number) => {
if (value < 0.2) {
return 'Nemesis';
} else if (value < 0.5) {
return 'Enemies';
} else if (value < 0.9) {
return 'Bad vibes';
} else if (value < 1.1) {
return 'Neutral';
} else if (value < 1.5) {
return 'Good vibes';
} else if (value < 1.8) {
return 'Good friends';
} else {
return 'Besties';
}
}
return (
<>
<Slider value={value} min={0} max={2} step={.1} onChange={(e) => onChange(toNumber(e.value))} className='w-80 bg-gray-400' />
<span className="px-4 w-1/5">
{label(value)}
</span>
</>
)
}

View File

@ -0,0 +1,34 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import React, { useState } from 'react';
export default function InlineTextField({ initialValue, onChange }: { initialValue: string, onChange: (value: string) => void }) {
const [editing, setEditing] = useState(false);
const [value, setValue] = useState(initialValue);
const renderText = () => <span onClick={() => setEditing(true)}>{value}</span>
const onConfirm = () => {
onChange(value);
setEditing(false);
}
function renderForm() {
return (
<div className="flex flex-row">
<input
type="text"
value={value}
className="px-2 py-0 h-5 max-w-48"
onChange={(e) => setValue(e.target.value)}
onBlur={onConfirm}
autoFocus
/>
</div>
)
}
return (
editing ? (renderForm()) : (renderText())
);
}

View File

@ -0,0 +1,95 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { AbstractApi } from '@/app/api/abstract-api';
import { Group, GroupSerializer } from '@/app/lib/group';
import { classNames } from '@/app/ui/components/button';
import { ColorPicker } from 'primereact/colorpicker';
import { Dialog } from 'primereact/dialog';
import { Dropdown } from 'primereact/dropdown';
import { FloatLabel } from 'primereact/floatlabel';
import { InputText } from 'primereact/inputtext';
import { useState } from 'react';
export default function GroupFormDialog({ groups, onCreate, onHide, group, visible }: {
groups: Group[],
onCreate?: () => void,
onHide: () => void,
group?: Group,
visible: boolean,
}) {
const [name, setName] = useState(group?.name || '');
const [icon, setIcon] = useState(group?.icon || '');
const [color, setColor] = useState<string>(group?.color || '');
const [parentId, setParentId] = useState(group?.parentId || '');
const api = new AbstractApi<Group>();
const serializer = new GroupSerializer();
function resetForm() {
setName('');
setIcon('');
setColor('');
setParentId('');
}
function submitGroup() {
if (!(name)) {
return
}
if (group?.id !== undefined) {
group.name = name;
group.icon = icon;
group.color = color;
group.parentId = parentId;
api.update(serializer, group, () => {
resetForm();
onCreate && onCreate();
});
} else {
api.create(serializer, new Group(undefined, name, undefined, icon, undefined, parentId, color), () => {
resetForm();
onCreate && onCreate();
});
}
}
return (
<>
<Dialog header="Add group" visible={visible} style={{ width: '60vw' }} onHide={onHide}>
<div className="card flex justify-evenly py-5">
<FloatLabel>
<InputText id="name" className='rounded-sm' value={name} onChange={(e) => setName(e.target.value)} />
<label htmlFor="name">Name</label>
</FloatLabel>
<FloatLabel>
<InputText id="icon" className='rounded-sm' value={icon} onChange={(e) => setIcon(e.target.value)} />
<label htmlFor="icon">Icon</label>
</FloatLabel>
<FloatLabel>
<ColorPicker value={color} format='hex' onChange={(e) => setColor(`#${e.value}`)} />
<label htmlFor="color" />
</FloatLabel>
<FloatLabel>
<Dropdown id="parentId" className='rounded-sm min-w-32' value={parentId} onChange={(e) => setParentId(e.target.value)} options={
groups.map((group) => {
return { label: group.name, value: group.id };
})
} />
<label htmlFor="parentId">Parent</label>
</FloatLabel>
<button className={classNames('primary')} onClick={submitGroup} disabled={!(name.length > 0)}>
{group?.id !== undefined ? 'Update' : 'Create'}
</button>
</div>
</Dialog>
</>
);
}

View File

@ -0,0 +1,91 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { AbstractApi } from '@/app/api/abstract-api';
import { Group } from '@/app/lib/group';
import { Guest, GuestSerializer, GuestStatus, guestStatuses } from '@/app/lib/guest';
import { capitalize } from '@/app/lib/utils';
import { classNames } from '@/app/ui/components/button';
import { Dialog } from 'primereact/dialog';
import { Dropdown } from 'primereact/dropdown';
import { FloatLabel } from 'primereact/floatlabel';
import { InputText } from 'primereact/inputtext';
import { useState } from 'react';
export default function GuestFormDialog({ groups, onCreate, onHide, guest, visible }: {
groups: Group[],
onCreate?: () => void,
onHide: () => void,
guest?: Guest,
visible: boolean,
}) {
const [name, setName] = useState(guest?.name || '');
const [group, setGroup] = useState(guest?.groupId || null);
const [status, setStatus] = useState<GuestStatus | null>(guest?.status || null);
const api = new AbstractApi<Guest>();
const serializer = new GuestSerializer();
function resetForm() {
setName('');
setGroup(null);
setStatus(null);
}
function submitGuest() {
if (!(name && group && status)) {
return
}
if (guest?.id !== undefined) {
guest.name = name;
guest.groupId = group;
guest.status = status;
api.update(serializer, guest, () => {
resetForm();
onCreate && onCreate();
});
} else {
api.create(serializer, new Guest(undefined, name, undefined, group, undefined, status), ()=> {
resetForm();
onCreate && onCreate();
});
}
}
return (
<>
<Dialog header="Add guest" visible={visible} style={{ width: '60vw' }} onHide={onHide}>
<div className="card flex justify-evenly py-5">
<FloatLabel>
<InputText id="username" className='rounded-sm' value={name} onChange={(e) => setName(e.target.value)} />
<label htmlFor="username">Username</label>
</FloatLabel>
<FloatLabel>
<Dropdown id="group" className='rounded-sm min-w-32' value={group} onChange={(e) => setGroup(e.target.value)} options={
groups.map((group) => {
return { label: group.name, value: group.id };
})
} />
<label htmlFor="group">Group</label>
</FloatLabel>
<FloatLabel>
<Dropdown id="status" className='rounded-sm min-w-32' value={status} onChange={(e) => setStatus(e.target.value)} options={
guestStatuses.map((status) => {
return { label: capitalize(status), value: status };
})
} />
<label htmlFor="status">Status</label>
</FloatLabel>
<button className={classNames('primary')} onClick={submitGuest} disabled={!(name.length > 0 && group && status)}>
{guest?.id !== undefined ? 'Update' : 'Create'}
</button>
</div>
</Dialog>
</>
);
}

View File

@ -0,0 +1,51 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { FloatLabel } from 'primereact/floatlabel';
import { InputText } from 'primereact/inputtext';
import { login } from '../../api/authentication';
import { useState, useEffect } from 'react';
import { classNames } from './button';
import { useRouter } from 'next/navigation'
import { User } from '../../lib/definitions';
import { getSlug } from '@/app/lib/utils';
export default function LoginForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const router = useRouter();
const [currentUser, setCurrentUser] = useState<User | null>(null);
useEffect(() => {
localStorage.setItem('currentUser', JSON.stringify(currentUser));
}, [currentUser]);
return (
<div className="card flex justify-evenly py-5">
<FloatLabel>
<InputText id="email" type="email" className='rounded-sm' onChange={(e) => setEmail(e.target.value)} />
<label htmlFor="email">Email</label>
</FloatLabel>
<FloatLabel>
<InputText id="password" type="password" className='rounded-sm' onChange={(e) => setPassword(e.target.value)} />
<label htmlFor="password">Password</label>
</FloatLabel>
<button
className={classNames('primary')}
disabled={email.length == 0 || password.length == 0}
onClick={() => login({
email: email,
password: password,
onLogin: (user) => {
setCurrentUser(user);
router.push(`${getSlug()}/dashboard`)
}
})}>
Sign in
</button>
</div>
)
}

View File

@ -0,0 +1,98 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { FloatLabel } from 'primereact/floatlabel';
import { InputText } from 'primereact/inputtext';
import { useState, useEffect } from 'react';
import { classNames } from './button';
import { getSlug } from '@/app/lib/utils';
import { register } from '@/app/api/authentication';
import { getCaptchaChallenge } from '@/app/api/captcha';
export default function RegistrationForm() {
const [submitted, setSubmitted] = useState<boolean>(false);
const [errors, setErrors] = useState<string[]>([]);
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [passwordConfirmation, setPasswordConfirmation] = useState<string>("");
const [slug, setSlug] = useState<string>(getSlug());
const [captchaId, setCaptchaId] = useState<string>("");
const [captchaUrl, setCaptchaUrl] = useState<string>("");
const [captchaAnswer, setCaptchaAnswer] = useState<string>("");
const refreshCaptcha = () => {
getCaptchaChallenge({
onRetrieve: (id, url) => {
console.log(id, url);
setCaptchaId(id);
setCaptchaUrl(url);
setCaptchaAnswer("");
}
});
}
useEffect(refreshCaptcha, [])
return (
submitted ? (
<div className="card flex justify-evenly py-5 flex-col">
<div className="text-green-500">Registration successful. Check your email for a confirmation link.</div>
</div>
) : (
<div className="card flex justify-evenly py-5 flex-col">
<FloatLabel className="my-4">
<InputText id="email" type="email" className='rounded-sm' onChange={(e) => setEmail(e.target.value)} />
<label htmlFor="email">Email</label>
</FloatLabel>
<FloatLabel className="my-4">
<InputText id="password" type="password" className='rounded-sm' onChange={(e) => setPassword(e.target.value)} />
<label htmlFor="password">Password</label>
</FloatLabel>
<FloatLabel className="my-4">
<InputText id="passwordConfirmation" type="password" className='rounded-sm' onChange={(e) => setPasswordConfirmation(e.target.value)} />
<label htmlFor="passwordConfirmation">Confirm Password</label>
</FloatLabel>
<FloatLabel className="my-4">
<InputText id="slug" type="text" className='rounded-sm' onChange={(e) => setSlug(e.target.value)} />
<label htmlFor="slug">Slug</label>
</FloatLabel>
<img className="w-96" src={captchaUrl} alt="captcha" />
<FloatLabel className="my-4">
<InputText id="captcha" type="text" className='rounded-sm' value={captchaAnswer} onChange={(e) => setCaptchaAnswer(e.target.value)} />
<label htmlFor="captcha">Captcha</label>
</FloatLabel>
{errors.map((error, index) => (
<div key={index} className="text-red-500">{error}</div>
))}
<button
className={classNames('primary')}
disabled={!(email && password && passwordConfirmation && slug && captchaAnswer)}
onClick={() => register(
{
slug: slug,
email: email,
password: password,
passwordConfirmation: passwordConfirmation,
captcha: {
id: captchaId,
answer: captchaAnswer
},
onRegister: () => { setErrors([]); setSubmitted(true) },
onError: (errors) => { refreshCaptcha(); setErrors(errors) }
}
)}
>
Register
</button>
</div>
)
);
}

View File

@ -0,0 +1,28 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
export default function TableOfContents<Type>({ headers, caption, elements, rowRender }: { headers: string[], caption: string, elements: Type[], rowRender: (element: Type) => JSX.Element }) {
return (
<div className="w-full relative overflow-x-auto shadow-md sm:rounded-lg">
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<caption className="p-5 text-lg font-semibold text-left rtl:text-right text-gray-900 bg-white dark:text-white dark:bg-gray-800">
{caption}
<p className="mt-1 text-sm font-normal text-gray-500 dark:text-gray-400">
There are {elements.length} elements in the list
</p>
</caption>
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
{headers.map((header) => (
<th scope="col" className="px-6 py-3">
{header}
</th>
))}
</tr>
</thead>
<tbody>
{elements.map((element) => rowRender(element))}
</tbody>
</table>
</div>
)
}

107
app/ui/components/table.tsx Normal file
View File

@ -0,0 +1,107 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Guest } from "@/app/lib/guest";
import { Table as TableType } from "@/app/lib/tableSimulation";
import { RectangleGroupIcon, UserGroupIcon } from "@heroicons/react/24/outline";
import { v4 as uuidv4 } from 'uuid';
import { Tooltip } from "primereact/tooltip";
import clsx from "clsx";
function Dish({ guest, rotation }: { guest: Guest, rotation?: number }) {
rotation = rotation || 0
return (
<div className={`m-3 w-24 h-24 rounded-full content-center text-center cursor-default`} style={{
rotate: `${360 - rotation}deg`,
backgroundColor: guest.color,
}}>
{guest.name}
</div>
)
}
function GuestRow({ guests }: { guests: Guest[] }) {
return (
<div className="justify-around flex flex-row">
{guests.map((guest) => <Dish key={guest.id} guest={guest} />)}
</div>
)
}
function RectangularTable({ table }: { table: TableType }) {
const guests = table.guests;
const halfwayThrough = Math.floor(guests.length / 2)
const arrayFirstHalf = guests.slice(0, halfwayThrough);
const arraySecondHalf = guests.slice(halfwayThrough, guests.length);
return (
<div className="m-12 h-64 bg-cyan-800 flex flex-col justify-between">
<GuestRow guests={arrayFirstHalf} />
<GuestRow guests={arraySecondHalf} />
</div>
)
}
function RoundedTable({ table }: { table: TableType }) {
const guests = table.guests;
const size = 500
const rotation = 360 / guests.length
const className = (penalty: number) => {
return clsx("px-2 tooltip-cohesion", {
"hidden": penalty === 0,
"text-orange-300": penalty <= 5,
"text-orange-500": penalty > 5 && penalty <= 10,
"text-orange-700": penalty > 10,
})
}
return (
<div className={`m-12 rounded-full bg-cyan-800 relative z-0 grid flex items-center justify-items-center`} style={{ width: `${size}px`, height: `${size}px` }}>
{
guests.map((guest, index) => {
return (
<div key={guest.id} className={`border-dashed grid justify-items-center absolute inset-0`} style={{
rotate: `${index * rotation}deg`,
height: `${size}px`,
width: `${size}px`,
}}>
<Dish guest={guest} rotation={index * rotation} />
</div>
)
})
}
<div className="bg-zinc-200 w-48 h-12 p-3 flex flex-row rounded z-10">
<div className="px-2 text-slate-800">{`Table #${table.number}`}</div>
<Tooltip target=".tooltip-cohesion" />
<Tooltip target=".tooltip-size" />
<RectangleGroupIcon
className={className(table.discomfort.breakdown.cohesionPenalty)}
data-pr-tooltip={`Cohesion penalty: ${Math.round(table.discomfort.breakdown.cohesionPenalty)}`}
data-pr-position="top"
/>
<UserGroupIcon
className={className(table.discomfort.breakdown.tableSizePenalty)}
data-pr-tooltip={`Table size penalty: ${Math.round(table.discomfort.breakdown.tableSizePenalty)}`}
data-pr-position="top"
/>
</div>
</div>
)
}
export function Table({ table, style }: { table: TableType, style: "rectangular" | "rounded" }) {
return (
<>
{style === "rectangular" && <RectangularTable table={table} />}
{style === "rounded" && <RoundedTable table={table} />}
</>
)
}

View File

@ -1,123 +0,0 @@
import Image from 'next/image';
import { lusitana } from '@/app/ui/fonts';
import Search from '@/app/ui/search';
import {
CustomersTableType,
FormattedCustomersTable,
} from '@/app/lib/definitions';
export default async function CustomersTable({
customers,
}: {
customers: FormattedCustomersTable[];
}) {
return (
<div className="w-full">
<h1 className={`${lusitana.className} mb-8 text-xl md:text-2xl`}>
Customers
</h1>
<Search placeholder="Search customers..." />
<div className="mt-6 flow-root">
<div className="overflow-x-auto">
<div className="inline-block min-w-full align-middle">
<div className="overflow-hidden rounded-md bg-gray-50 p-2 md:pt-0">
<div className="md:hidden">
{customers?.map((customer) => (
<div
key={customer.id}
className="mb-2 w-full rounded-md bg-white p-4"
>
<div className="flex items-center justify-between border-b pb-4">
<div>
<div className="mb-2 flex items-center">
<div className="flex items-center gap-3">
<Image
src={customer.image_url}
className="rounded-full"
alt={`${customer.name}'s profile picture`}
width={28}
height={28}
/>
<p>{customer.name}</p>
</div>
</div>
<p className="text-sm text-gray-500">
{customer.email}
</p>
</div>
</div>
<div className="flex w-full items-center justify-between border-b py-5">
<div className="flex w-1/2 flex-col">
<p className="text-xs">Pending</p>
<p className="font-medium">{customer.total_pending}</p>
</div>
<div className="flex w-1/2 flex-col">
<p className="text-xs">Paid</p>
<p className="font-medium">{customer.total_paid}</p>
</div>
</div>
<div className="pt-4 text-sm">
<p>{customer.total_guests} guests</p>
</div>
</div>
))}
</div>
<table className="hidden min-w-full rounded-md text-gray-900 md:table">
<thead className="rounded-md bg-gray-50 text-left text-sm font-normal">
<tr>
<th scope="col" className="px-4 py-5 font-medium sm:pl-6">
Name
</th>
<th scope="col" className="px-3 py-5 font-medium">
Email
</th>
<th scope="col" className="px-3 py-5 font-medium">
Total guests
</th>
<th scope="col" className="px-3 py-5 font-medium">
Total Pending
</th>
<th scope="col" className="px-4 py-5 font-medium">
Total Paid
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 text-gray-900">
{customers.map((customer) => (
<tr key={customer.id} className="group">
<td className="whitespace-nowrap bg-white py-5 pl-4 pr-3 text-sm text-black group-first-of-type:rounded-md group-last-of-type:rounded-md sm:pl-6">
<div className="flex items-center gap-3">
<Image
src={customer.image_url}
className="rounded-full"
alt={`${customer.name}'s profile picture`}
width={28}
height={28}
/>
<p>{customer.name}</p>
</div>
</td>
<td className="whitespace-nowrap bg-white px-4 py-5 text-sm">
{customer.email}
</td>
<td className="whitespace-nowrap bg-white px-4 py-5 text-sm">
{customer.total_guests}
</td>
<td className="whitespace-nowrap bg-white px-4 py-5 text-sm">
{customer.total_pending}
</td>
<td className="whitespace-nowrap bg-white px-4 py-5 text-sm group-first-of-type:rounded-md group-last-of-type:rounded-md">
{customer.total_paid}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -1,58 +0,0 @@
import {
BanknotesIcon,
ClockIcon,
UserGroupIcon,
InboxIcon,
} from '@heroicons/react/24/outline';
import { lusitana } from '@/app/ui/fonts';
const iconMap = {
collected: BanknotesIcon,
customers: UserGroupIcon,
pending: ClockIcon,
guests: InboxIcon,
};
export default async function CardWrapper() {
return (
<>
{/* NOTE: Uncomment this code in Chapter 9 */}
{/* <Card title="Collected" value={totalPaidguests} type="collected" />
<Card title="Pending" value={totalPendingguests} type="pending" />
<Card title="Total guests" value={numberOfguests} type="guests" />
<Card
title="Total Customers"
value={numberOfCustomers}
type="customers"
/> */}
</>
);
}
export function Card({
title,
value,
type,
}: {
title: string;
value: number | string;
type: 'guests' | 'customers' | 'pending' | 'collected';
}) {
const Icon = iconMap[type];
return (
<div className="rounded-xl bg-gray-50 p-2 shadow-sm">
<div className="flex p-4">
{Icon ? <Icon className="h-5 w-5 text-gray-700" /> : null}
<h3 className="ml-2 text-sm font-medium">{title}</h3>
</div>
<p
className={`${lusitana.className}
truncate rounded-xl bg-white px-4 py-8 text-center text-2xl`}
>
{value}
</p>
</div>
);
}

View File

@ -0,0 +1,41 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { GlobalSummary as Summary} from '@/app/lib/definitions';
import { MainCard, SecondaryCard } from '../components/dashboard-cards';
export default function GlobalSummary({ summary }: { summary: Summary }) {
return (
<div className="my-4">
<div className="flex flex-row w-full my-2">
<div className="flex flex-col">
<MainCard amount={`${summary.expenses.projected.total}`} title="Projected" subtitle={`${summary.expenses.projected.guests} guests`} style="blue" iconName="ArrowTrendingUpIcon" />
<MainCard amount={`${Math.round(summary.expenses.projected.total / summary.expenses.projected.guests)}`} title="/ guest" iconName="UserIcon" style='blue' />
</div>
<div className="flex flex-col">
<MainCard amount={`${summary.expenses.confirmed.total}`} title="Min." subtitle={`${summary.expenses.confirmed.guests} guests`} iconName="ChevronDoubleDownIcon" style="green" />
<MainCard amount={`${Math.round(summary.expenses.confirmed.total / summary.expenses.confirmed.guests)}`} title="/ guest" iconName="UserIcon" style='green' />
</div>
<div className="flex flex-col">
<MainCard amount={`${summary.expenses.status.paid}`} title="Paid already" subtitle={`${Math.round(summary.expenses.status.paid / summary.expenses.projected.total * 100)}% of projected`} iconName="CheckIcon" style='blue' />
<MainCard amount={`${summary.expenses.projected.total - summary.expenses.status.paid}`} title="To pay" subtitle={`${100 - Math.round(summary.expenses.status.paid / summary.expenses.projected.total * 100)}% of projected`} iconName="BanknotesIcon" style="orange" />
</div>
</div>
<div className="flex flex-row w-full my-2">
<MainCard style="blue" amount={summary.guests.total.toString()} title="Invites sent" iconName="UsersIcon" />
<div className="flex flex-col">
<SecondaryCard amount={`${Math.round(summary.guests.confirmed / summary.guests.total * 100)}%`} title={`confirmed (${summary.guests.confirmed} guests)`} iconName="CheckIcon" style='green' />
<SecondaryCard amount={`${Math.round(summary.guests.declined / summary.guests.total * 100)}%`} title={`declined (${summary.guests.declined} guests)`} iconName="XMarkIcon" style='red' />
</div>
<div className="flex flex-col">
<SecondaryCard amount={`${Math.round(summary.guests.tentative / summary.guests.total * 100)}%`} title={`tentative (${summary.guests.tentative} guests)`} iconName="QuestionMarkCircleIcon" style='orange' />
<SecondaryCard amount={`${Math.round(summary.guests.invited / summary.guests.total * 100)}%`} title={`awaiting (${summary.guests.invited} guests)`} iconName="EllipsisHorizontalIcon" style='gray' />
</div>
</div>
</div>
);
}

View File

@ -1,64 +0,0 @@
import { ArrowPathIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import Image from 'next/image';
import { lusitana } from '@/app/ui/fonts';
import { LatestInvoice } from '@/app/lib/definitions';
export default async function Latestguests({
latestguests,
}: {
latestguests: LatestInvoice[];
}) {
return (
<div className="flex w-full flex-col md:col-span-4">
<h2 className={`${lusitana.className} mb-4 text-xl md:text-2xl`}>
Latest guests
</h2>
<div className="flex grow flex-col justify-between rounded-xl bg-gray-50 p-4">
{/* NOTE: Uncomment this code in Chapter 7 */}
{/* <div className="bg-white px-6">
{latestguests.map((invoice, i) => {
return (
<div
key={invoice.id}
className={clsx(
'flex flex-row items-center justify-between py-4',
{
'border-t': i !== 0,
},
)}
>
<div className="flex items-center">
<Image
src={invoice.image_url}
alt={`${invoice.name}'s profile picture`}
className="mr-4 rounded-full"
width={32}
height={32}
/>
<div className="min-w-0">
<p className="truncate text-sm font-semibold md:text-base">
{invoice.name}
</p>
<p className="hidden text-sm text-gray-500 sm:block">
{invoice.email}
</p>
</div>
</div>
<p
className={`${lusitana.className} truncate text-sm font-medium md:text-base`}
>
{invoice.amount}
</p>
</div>
);
})}
</div> */}
<div className="flex items-center pb-2 pt-6">
<ArrowPathIcon className="h-5 w-5 text-gray-500" />
<h3 className="ml-2 text-sm text-gray-500 ">Updated just now</h3>
</div>
</div>
</div>
);
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
export default function Loading() {
return <div>Loading...</div>;
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client'
import {
@ -8,13 +10,14 @@ import {
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
import { getSlug } from '@/app/lib/utils';
// Map of links to display in the side navigation.
// Depending on the size of the application, this would be stored in a database.
const links = [
{ name: 'Guests', href: '/dashboard/guests', icon: UserGroupIcon },
{ name: 'Expenses', href: '/dashboard/expenses', icon: BanknotesIcon },
{ name: 'Table distributions', href: '/dashboard/tables', icon: RectangleGroupIcon },
{ name: 'Guests', href: `/${getSlug()}/dashboard/guests`, icon: UserGroupIcon },
{ name: 'Expenses', href: `/${getSlug()}/dashboard/expenses`, icon: BanknotesIcon },
{ name: 'Table distributions', href: `/${getSlug()}/dashboard/tables`, icon: RectangleGroupIcon },
];

View File

@ -1,65 +0,0 @@
import { generateYAxis } from '@/app/lib/utils';
import { CalendarIcon } from '@heroicons/react/24/outline';
import { lusitana } from '@/app/ui/fonts';
import { Revenue } from '@/app/lib/definitions';
// This component is representational only.
// For data visualization UI, check out:
// https://www.tremor.so/
// https://www.chartjs.org/
// https://airbnb.io/visx/
export default async function RevenueChart({
revenue,
}: {
revenue: Revenue[];
}) {
const chartHeight = 350;
// NOTE: Uncomment this code in Chapter 7
// const { yAxisLabels, topLabel } = generateYAxis(revenue);
// if (!revenue || revenue.length === 0) {
// return <p className="mt-4 text-gray-400">No data available.</p>;
// }
return (
<div className="w-full md:col-span-4">
<h2 className={`${lusitana.className} mb-4 text-xl md:text-2xl`}>
Recent Revenue
</h2>
{/* NOTE: Uncomment this code in Chapter 7 */}
{/* <div className="rounded-xl bg-gray-50 p-4">
<div className="sm:grid-cols-13 mt-0 grid grid-cols-12 items-end gap-2 rounded-md bg-white p-4 md:gap-4">
<div
className="mb-6 hidden flex-col justify-between text-sm text-gray-400 sm:flex"
style={{ height: `${chartHeight}px` }}
>
{yAxisLabels.map((label) => (
<p key={label}>{label}</p>
))}
</div>
{revenue.map((month) => (
<div key={month.month} className="flex flex-col items-center gap-2">
<div
className="w-full rounded-md bg-blue-300"
style={{
height: `${(chartHeight / topLabel) * month.revenue}px`,
}}
></div>
<p className="-rotate-90 text-sm text-gray-400 sm:rotate-0">
{month.month}
</p>
</div>
))}
</div>
<div className="flex items-center pb-2 pt-6">
<CalendarIcon className="h-5 w-5 text-gray-500" />
<h3 className="ml-2 text-sm text-gray-500 ">Last 12 months</h3>
</div>
</div> */}
</div>
);
}

View File

@ -1,28 +1,46 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import Link from 'next/link';
import NavLinks from '@/app/ui/dashboard/nav-links';
import { PowerIcon } from '@heroicons/react/24/outline';
import { gloriaHallelujah } from '@/app/ui/fonts';
import { logout } from '@/app/api/authentication';
import { useRouter } from 'next/navigation';
import { getSlug } from '@/app/lib/utils';
export default function SideNav() {
const router = useRouter();
return (
<div className="flex h-full flex-col px-3 py-4 md:px-2">
<Link
className="mb-2 flex h-20 items-center justify-start rounded-md bg-blue-600 p-4 md:h-20"
href="/dashboard/guests"
href={`/${getSlug()}/dashboard`}
>
<div className={`${gloriaHallelujah.className} "w-32 text-white md:w-40 antialiased` }>
<div className={`${gloriaHallelujah.className} "w-32 text-white md:w-40 antialiased`}>
<h1>Wedding Planner</h1>
</div>
</Link>
<div className="flex grow flex-row justify-between space-x-2 md:flex-col md:space-x-0 md:space-y-2">
<NavLinks />
<div className="hidden h-auto w-full grow rounded-md bg-gray-50 md:block"></div>
<form>
<button className="flex h-[48px] w-full grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3">
<PowerIcon className="w-6" />
<div className="hidden md:block">Sign Out</div>
</button>
</form>
<span>Logged in as {JSON.parse(localStorage.getItem('currentUser') || '{}').email}</span>
<button
className="flex h-[48px] w-full grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
onClick={() => {
logout({
onLogout: () => {
localStorage.clear();
router.push(`/${getSlug()}`);
}
});
}}
>
<PowerIcon className="w-6" />
<div className="hidden md:block">Sign Out</div>
</button>
</div>
</div>
);

46
app/ui/expenses/table.tsx Normal file
View File

@ -0,0 +1,46 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client'
import { AbstractApi } from '@/app/api/abstract-api';
import { Expense, ExpenseSerializer } from '@/app/lib/expense';
import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline';
import TableOfContents from "../components/table-of-contents";
export default function ExpensesTable({ expenses, onUpdate, onEdit }: {
expenses: Expense[],
onUpdate: () => void,
onEdit: (expense: Expense) => void,
}) {
const api = new AbstractApi<Expense>();
const serializer = new ExpenseSerializer();
return (
<TableOfContents
headers={['Name', 'Amount (€)', 'Pricing Type', 'Actions']}
caption='Expenses'
elements={expenses}
rowRender={(expense) => (
<tr key={expense.id} className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800">
<th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{expense.name}
</th>
<td className="px-6 py-4">
{expense.amount}
</td>
<td>
{expense.pricingType}
</td>
<td>
<div className="flex flex-row items-center">
<TrashIcon className='size-6 cursor-pointer' onClick={() => { api.destroy(serializer, expense, onUpdate) }} />
<PencilIcon className='size-6 cursor-pointer' onClick={() => onEdit(expense)} />
</div>
</td>
</tr>
)}
/>
);
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Inter, Lusitana, Gloria_Hallelujah} from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });

105
app/ui/groups/table.tsx Normal file
View File

@ -0,0 +1,105 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { AbstractApi } from '@/app/api/abstract-api';
import { Group, GroupSerializer } from '@/app/lib/group';
import { AdjustmentsHorizontalIcon, PencilIcon, TrashIcon } from '@heroicons/react/24/outline';
import { Column } from 'primereact/column';
import { TreeNode } from 'primereact/treenode';
import { TreeTable } from 'primereact/treetable';
export default function GroupsTable({ groups, onUpdate, onEdit, onEditAffinities }: {
groups: Group[],
onUpdate: () => void,
onEdit: (group: Group) => void,
onEditAffinities: (group: Group) => void,
}) {
const api = new AbstractApi<Group>();
const serializer = new GroupSerializer();
const actions = (group: Group) => (
<div className="flex flex-row items-center">
<TrashIcon className='size-6 cursor-pointer' onClick={() => { api.destroy(serializer, group, onUpdate) }} />
<PencilIcon className='size-6 cursor-pointer' onClick={() => onEdit(group)} />
<AdjustmentsHorizontalIcon className='size-6 cursor-pointer' onClick={() => onEditAffinities(group)} />
</div>
);
const index = groups.reduce((acc, group) => {
if (group.id) {
acc.set(group.id, group)
}
return acc;
}, new Map());
groups.forEach(group => group.children = []);
groups.forEach(group => {
if (group.parentId) {
const parent = index.get(group.parentId);
if (parent) {
if (!parent.children) {
parent.children = [];
}
parent.children.push(group);
}
}
});
const renderTree = (group: Group): TreeNode => {
const childrenAttendance = (group.children || []).reduce((acc, child) => {
acc.confirmed += child.attendance?.confirmed || 0;
acc.tentative += child.attendance?.tentative || 0;
acc.invited += child.attendance?.invited || 0;
acc.declined += child.attendance?.declined || 0;
acc.considered += child.attendance?.considered || 0;
acc.total += child.attendance?.total || 0;
return acc;
}, { confirmed: 0, tentative: 0, invited: 0, declined: 0, considered: 0, total: 0 });
return {
id: group.id,
key: group.id,
label: group.name,
data: {
name: group.name,
color: <div className="w-8 h-8 rounded-full" style={{ backgroundColor: group.color }} />,
confirmed: childrenAttendance.confirmed + (group.attendance?.confirmed || 0),
tentative: childrenAttendance.tentative + (group.attendance?.tentative || 0),
pending: childrenAttendance.invited + (group.attendance?.invited || 0),
declined: childrenAttendance.declined + (group.attendance?.declined || 0),
considered: childrenAttendance.considered + (group.attendance?.considered || 0),
total: childrenAttendance.total + (group.attendance?.total || 0),
actions: actions(group),
},
children: group.children?.map(renderTree),
}
}
const nodes: TreeNode[] = groups
.filter(group => !group.parentId)
.map(renderTree)
const headers = ['Name', 'Color', 'Confirmed', 'Tentative', 'Pending', 'Declined', 'Considered', 'Total', 'Actions'];
const rowClassName = () => {
return { 'border-b odd:bg-white even:bg-gray-50 hover:bg-gray-100': true };
}
return (
<>
<TreeTable value={nodes} rowClassName={rowClassName} className='py-4'>
<Column expander field="name" header="Name" className='w-2/5' />
<Column field="color" header="Color" bodyClassName="text-sm" />
<Column field="confirmed" header="Confirmed" bodyClassName="text-sm" />
<Column field="tentative" header="Tentative" bodyClassName="text-sm" />
<Column field="pending" header="Pending" bodyClassName="text-sm" />
<Column field="declined" header="Declined" bodyClassName="text-sm" />
<Column field="considered" header="Considered" bodyClassName="text-sm" />
<Column field="total" header="Total" bodyClassName="text-sm" />
<Column field="actions" header="Actions" />
</TreeTable>
</>
)
}

View File

@ -1,63 +0,0 @@
'use client'
import React, { useState, useEffect, Suspense } from 'react';
import { Tree } from 'primereact/tree';
import { PrimeIcons } from 'primereact/api';
import { debug } from 'console';
import { Group } from '@/app/lib/definitions';
export default function AffinityGroupsTree() {
const [nodes, setNodes] = useState([]);
const groupToNode = (group: Group): any => {
return({
key: group.id,
label: `${group.name} (${group.guest_count})`,
icon: group.icon,
children: group.children.map((child) => groupToNode(child)),
className: "px-4",
})
}
const parseNode = (record: any, included: any[]): Group => {
if (!record.attributes) {
record = included.find((a) => a.id === record.id);
}
const children: Group[] = (record?.relationships?.children?.data || []).map((child: any) => {
return (parseNode(child, included));
});
const children_guest_count: number = children.reduce((acc: number, child: Group) => acc + child.guest_count, 0);
return ({
id: record.id,
name: record.attributes.name,
guest_count: record.attributes.guest_count + children_guest_count,
icon: record.attributes.icon,
children: children,
})
}
useEffect(() => {
if (nodes.length > 0) {
return;
}
fetch("http://localhost:3001/groups.json")
.then((response) => response.json())
.then((data) => {
setNodes(data.data.map((record: any) => {
return (groupToNode(parseNode(record, data.included)));
}))
});
});
return (
<div className="card flex justify-content-center">
<Suspense>
<Tree value={nodes} dragdropScope="affinity-groups" onDragDrop={(e) => setNodes(e.value as any)} className="w-full md:w-30rem" />
</Suspense>
</div>
)
}

View File

@ -1,36 +0,0 @@
import { clsx } from 'clsx';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
interface Breadcrumb {
label: string;
href: string;
active?: boolean;
}
export default function Breadcrumbs({
breadcrumbs,
}: {
breadcrumbs: Breadcrumb[];
}) {
return (
<nav aria-label="Breadcrumb" className="mb-6 block">
<ol className={clsx(lusitana.className, 'flex text-xl md:text-2xl')}>
{breadcrumbs.map((breadcrumb, index) => (
<li
key={breadcrumb.href}
aria-current={breadcrumb.active}
className={clsx(
breadcrumb.active ? 'text-gray-900' : 'text-gray-500',
)}
>
<Link href={breadcrumb.href}>{breadcrumb.label}</Link>
{index < breadcrumbs.length - 1 ? (
<span className="mx-3 inline-block">/</span>
) : null}
</li>
))}
</ol>
</nav>
);
}

View File

@ -1,36 +0,0 @@
import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
export function CreateInvoice() {
return (
<Link
href="/dashboard/guests/create"
className="flex h-10 items-center rounded-lg bg-blue-600 px-4 text-sm font-medium text-white transition-colors hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
>
<span className="hidden md:block">Create Invoice</span>{' '}
<PlusIcon className="h-5 md:ml-4" />
</Link>
);
}
export function UpdateInvoice({ id }: { id: string }) {
return (
<Link
href="/dashboard/guests"
className="rounded-md border p-2 hover:bg-gray-100"
>
<PencilIcon className="w-5" />
</Link>
);
}
export function DeleteInvoice({ id }: { id: string }) {
return (
<>
<button className="rounded-md border p-2 hover:bg-gray-100">
<span className="sr-only">Delete</span>
<TrashIcon className="w-5" />
</button>
</>
);
}

View File

@ -1,112 +0,0 @@
import { CustomerField } from '@/app/lib/definitions';
import Link from 'next/link';
import {
CheckIcon,
ClockIcon,
CurrencyDollarIcon,
UserCircleIcon,
} from '@heroicons/react/24/outline';
import { Button } from '@/app/ui/button';
export default function Form({ customers }: { customers: CustomerField[] }) {
return (
<form>
<div className="rounded-md bg-gray-50 p-4 md:p-6">
{/* Customer Name */}
<div className="mb-4">
<label htmlFor="customer" className="mb-2 block text-sm font-medium">
Choose customer
</label>
<div className="relative">
<select
id="customer"
name="customerId"
className="peer block w-full cursor-pointer rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
defaultValue=""
>
<option value="" disabled>
Select a customer
</option>
{customers.map((customer) => (
<option key={customer.id} value={customer.id}>
{customer.name}
</option>
))}
</select>
<UserCircleIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500" />
</div>
</div>
{/* Invoice Amount */}
<div className="mb-4">
<label htmlFor="amount" className="mb-2 block text-sm font-medium">
Choose an amount
</label>
<div className="relative mt-2 rounded-md">
<div className="relative">
<input
id="amount"
name="amount"
type="number"
step="0.01"
placeholder="Enter USD amount"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
/>
<CurrencyDollarIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
</div>
</div>
{/* Invoice Status */}
<fieldset>
<legend className="mb-2 block text-sm font-medium">
Set the invoice status
</legend>
<div className="rounded-md border border-gray-200 bg-white px-[14px] py-3">
<div className="flex gap-4">
<div className="flex items-center">
<input
id="pending"
name="status"
type="radio"
value="pending"
className="h-4 w-4 cursor-pointer border-gray-300 bg-gray-100 text-gray-600 focus:ring-2"
/>
<label
htmlFor="pending"
className="ml-2 flex cursor-pointer items-center gap-1.5 rounded-full bg-gray-100 px-3 py-1.5 text-xs font-medium text-gray-600"
>
Pending <ClockIcon className="h-4 w-4" />
</label>
</div>
<div className="flex items-center">
<input
id="paid"
name="status"
type="radio"
value="paid"
className="h-4 w-4 cursor-pointer border-gray-300 bg-gray-100 text-gray-600 focus:ring-2"
/>
<label
htmlFor="paid"
className="ml-2 flex cursor-pointer items-center gap-1.5 rounded-full bg-green-500 px-3 py-1.5 text-xs font-medium text-white"
>
Paid <CheckIcon className="h-4 w-4" />
</label>
</div>
</div>
</div>
</fieldset>
</div>
<div className="mt-6 flex justify-end gap-4">
<Link
href="/dashboard/guests"
className="flex h-10 items-center rounded-lg bg-gray-100 px-4 text-sm font-medium text-gray-600 transition-colors hover:bg-gray-200"
>
Cancel
</Link>
<Button type="submit">Create Invoice</Button>
</div>
</form>
);
}

View File

@ -1,123 +0,0 @@
'use client';
import { CustomerField, InvoiceForm } from '@/app/lib/definitions';
import {
CheckIcon,
ClockIcon,
CurrencyDollarIcon,
UserCircleIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { Button } from '@/app/ui/button';
export default function EditInvoiceForm({
invoice,
customers,
}: {
invoice: InvoiceForm;
customers: CustomerField[];
}) {
return (
<form>
<div className="rounded-md bg-gray-50 p-4 md:p-6">
{/* Customer Name */}
<div className="mb-4">
<label htmlFor="customer" className="mb-2 block text-sm font-medium">
Choose customer
</label>
<div className="relative">
<select
id="customer"
name="customerId"
className="peer block w-full cursor-pointer rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
defaultValue={invoice.customer_id}
>
<option value="" disabled>
Select a customer
</option>
{customers.map((customer) => (
<option key={customer.id} value={customer.id}>
{customer.name}
</option>
))}
</select>
<UserCircleIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500" />
</div>
</div>
{/* Invoice Amount */}
<div className="mb-4">
<label htmlFor="amount" className="mb-2 block text-sm font-medium">
Choose an amount
</label>
<div className="relative mt-2 rounded-md">
<div className="relative">
<input
id="amount"
name="amount"
type="number"
step="0.01"
defaultValue={invoice.amount}
placeholder="Enter USD amount"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
/>
<CurrencyDollarIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
</div>
</div>
{/* Invoice Status */}
<fieldset>
<legend className="mb-2 block text-sm font-medium">
Set the invoice status
</legend>
<div className="rounded-md border border-gray-200 bg-white px-[14px] py-3">
<div className="flex gap-4">
<div className="flex items-center">
<input
id="pending"
name="status"
type="radio"
value="pending"
defaultChecked={invoice.status === 'pending'}
className="h-4 w-4 cursor-pointer border-gray-300 bg-gray-100 text-gray-600 focus:ring-2"
/>
<label
htmlFor="pending"
className="ml-2 flex cursor-pointer items-center gap-1.5 rounded-full bg-gray-100 px-3 py-1.5 text-xs font-medium text-gray-600"
>
Pending <ClockIcon className="h-4 w-4" />
</label>
</div>
<div className="flex items-center">
<input
id="paid"
name="status"
type="radio"
value="paid"
defaultChecked={invoice.status === 'paid'}
className="h-4 w-4 cursor-pointer border-gray-300 bg-gray-100 text-gray-600 focus:ring-2"
/>
<label
htmlFor="paid"
className="ml-2 flex cursor-pointer items-center gap-1.5 rounded-full bg-green-500 px-3 py-1.5 text-xs font-medium text-white"
>
Paid <CheckIcon className="h-4 w-4" />
</label>
</div>
</div>
</div>
</fieldset>
</div>
<div className="mt-6 flex justify-end gap-4">
<Link
href="/dashboard/guests"
className="flex h-10 items-center rounded-lg bg-gray-100 px-4 text-sm font-medium text-gray-600 transition-colors hover:bg-gray-200"
>
Cancel
</Link>
<Button type="submit">Edit Invoice</Button>
</div>
</form>
);
}

View File

@ -1,119 +0,0 @@
'use client';
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import Link from 'next/link';
import { generatePagination } from '@/app/lib/utils';
export default function Pagination({ totalPages }: { totalPages: number }) {
// NOTE: Uncomment this code in Chapter 11
// const allPages = generatePagination(currentPage, totalPages);
return (
<>
{/* NOTE: Uncomment this code in Chapter 11 */}
{/* <div className="inline-flex">
<PaginationArrow
direction="left"
href={createPageURL(currentPage - 1)}
isDisabled={currentPage <= 1}
/>
<div className="flex -space-x-px">
{allPages.map((page, index) => {
let position: 'first' | 'last' | 'single' | 'middle' | undefined;
if (index === 0) position = 'first';
if (index === allPages.length - 1) position = 'last';
if (allPages.length === 1) position = 'single';
if (page === '...') position = 'middle';
return (
<PaginationNumber
key={page}
href={createPageURL(page)}
page={page}
position={position}
isActive={currentPage === page}
/>
);
})}
</div>
<PaginationArrow
direction="right"
href={createPageURL(currentPage + 1)}
isDisabled={currentPage >= totalPages}
/>
</div> */}
</>
);
}
function PaginationNumber({
page,
href,
isActive,
position,
}: {
page: number | string;
href: string;
position?: 'first' | 'last' | 'middle' | 'single';
isActive: boolean;
}) {
const className = clsx(
'flex h-10 w-10 items-center justify-center text-sm border',
{
'rounded-l-md': position === 'first' || position === 'single',
'rounded-r-md': position === 'last' || position === 'single',
'z-10 bg-blue-600 border-blue-600 text-white': isActive,
'hover:bg-gray-100': !isActive && position !== 'middle',
'text-gray-300': position === 'middle',
},
);
return isActive || position === 'middle' ? (
<div className={className}>{page}</div>
) : (
<Link href={href} className={className}>
{page}
</Link>
);
}
function PaginationArrow({
href,
direction,
isDisabled,
}: {
href: string;
direction: 'left' | 'right';
isDisabled?: boolean;
}) {
const className = clsx(
'flex h-10 w-10 items-center justify-center rounded-md border',
{
'pointer-events-none text-gray-300': isDisabled,
'hover:bg-gray-100': !isDisabled,
'mr-2 md:mr-4': direction === 'left',
'ml-2 md:ml-4': direction === 'right',
},
);
const icon =
direction === 'left' ? (
<ArrowLeftIcon className="w-4" />
) : (
<ArrowRightIcon className="w-4" />
);
return isDisabled ? (
<div className={className}>{icon}</div>
) : (
<Link className={className} href={href}>
{icon}
</Link>
);
}

View File

@ -0,0 +1,36 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import Skeleton from '@/app/ui/skeleton';
export function SkeletonRow() {
return (
<tr className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800">
<td className="px-6 py-4">{<Skeleton className="w-[45ch] h-[1rem]" />}</td>
<td className="px-6 py-4">{<Skeleton className="w-[45ch] h-[1rem]" />}</td>
<td className="px-6 py-4">{<Skeleton className="w-[20ch] h-[1rem]" />}</td>
<td className="px-6 py-4">{<Skeleton className="w-[10ch] h-[1rem]" />}</td>
</tr>
);
}
export default function SkeletonTable() {
return (
<div className="w-full relative overflow-x-auto shadow-md sm:rounded-lg">
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<caption className="p-5 text-lg font-semibold text-left rtl:text-right text-gray-900 bg-white dark:text-white dark:bg-gray-800">
Guests
<p className="mt-1 text-sm font-normal text-gray-500 dark:text-gray-400">
Loading the list of guests...
</p>
</caption>
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
</thead>
<tbody>
{[...Array(20)].map((e, i) => <SkeletonRow />)}
</tbody>
</table>
</div>
);
}

View File

@ -1,29 +0,0 @@
import { CheckIcon, ClockIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
export default function gueststatus({ status }: { status: string }) {
return (
<span
className={clsx(
'inline-flex items-center rounded-full px-2 py-1 text-xs',
{
'bg-gray-100 text-gray-500': status === 'pending',
'bg-green-500 text-white': status === 'paid',
},
)}
>
{status === 'pending' ? (
<>
Pending
<ClockIcon className="ml-1 w-4 text-gray-500" />
</>
) : null}
{status === 'paid' ? (
<>
Paid
<CheckIcon className="ml-1 w-4 text-white" />
</>
) : null}
</span>
);
}

View File

@ -1,91 +1,59 @@
'use client'
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Guest } from '@/app/lib/definitions';
import { useState, Suspense, useEffect } from 'react';
'use client';
import { AbstractApi } from '@/app/api/abstract-api';
import { Guest , GuestSerializer} from '@/app/lib/guest';
import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import TableOfContents from '../components/table-of-contents';
export default function guestsTable() {
export default function guestsTable({ guests, onUpdate, onEdit }: {
guests: Guest[],
onUpdate: () => void,
onEdit: (guest: Guest) => void
}) {
const [guests, setGuests] = useState<Guest[]>([]);
useEffect(() => {
if (guests.length > 0) {
return;
}
fetch("http://localhost:3001/guests.json")
.then((response) => response.json())
.then((data) => {
setGuests(data.data.map((record: any) => {
return ({
id: record.id,
name: record.attributes.name,
email: record.attributes.email,
group_name: record.attributes.group_name,
status: record.attributes.status
});
}))
});
});
const api = new AbstractApi<Guest>();
const serializer = new GuestSerializer();
return (
<div className="w-full relative overflow-x-auto shadow-md sm:rounded-lg">
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<caption className="p-5 text-lg font-semibold text-left rtl:text-right text-gray-900 bg-white dark:text-white dark:bg-gray-800">
Guests
<p className="mt-1 text-sm font-normal text-gray-500 dark:text-gray-400">
There are {guests.length} guests in the list
</p>
</caption>
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="px-6 py-3">
Name
</th>
<th scope="col" className="px-6 py-3">
Email
</th>
<th scope="col" className="px-6 py-3">
Group
</th>
<th scope="col" className="px-6 py-3">
Status
</th>
</tr>
</thead>
<tbody>
<Suspense>
{guests.map((guest) => (
<tr key={guest.id} className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800">
<th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{guest.name}
</th>
<td className="px-6 py-4">
{guest.email}
</td>
<td className="px-6 py-4">
{guest.group_name}
</td>
<td className="px-6 py-4">
<span className="flex items-center text-sm dark:text-white me-3">
<span className={clsx(
'flex w-2.5 h-2.5 rounded-full me-1.5 flex-shrink-0',
{
'bg-gray-400': guest.status === 'Considered',
'bg-blue-400': guest.status === 'Invited',
'bg-green-600': guest.status === 'Confirmed',
'bg-red-400': guest.status === 'Declined',
}
)}>
{/* <span className="flex w-2.5 h-2.5 rounded-full me-1.5 flex-shrink-0 bg-blue-600"> */}
</span>
{guest.status}
</span>
</td>
</tr>
))}
</Suspense>
</tbody>
</table>
</div>
<TableOfContents
headers={['Name', 'Group', 'Status', 'Actions']}
caption='Guests'
elements={guests}
rowRender={(guest) => (
<tr key={guest.id} className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800">
<td scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{guest.name}
</td>
<td className="px-6 py-4">
{guest.group_name}
</td>
<td className="px-6 py-4">
<span className="flex items-center text-sm dark:text-white me-3">
<span className={clsx(
'flex w-2.5 h-2.5 rounded-full me-1.5 flex-shrink-0',
{
'bg-gray-400': guest.status === 'considered',
'bg-blue-400': guest.status === 'invited',
'bg-green-600': guest.status === 'confirmed',
'bg-red-400': guest.status === 'declined',
'bg-yellow-400': guest.status === 'tentative',
}
)}>
</span>
{guest.status}
</span>
</td>
<td>
<div className="flex flex-row items-center">
<TrashIcon className='size-6 cursor-pointer' onClick={() => { api.destroy(serializer, guest, onUpdate)}} />
<PencilIcon className='size-6 cursor-pointer' onClick={() => onEdit(guest)} />
</div>
</td>
</tr>
)}
/>
);
}

View File

@ -1,67 +0,0 @@
import { lusitana } from '@/app/ui/fonts';
import {
AtSymbolIcon,
KeyIcon,
ExclamationCircleIcon,
} from '@heroicons/react/24/outline';
import { ArrowRightIcon } from '@heroicons/react/20/solid';
import { Button } from './button';
export default function LoginForm() {
return (
<form className="space-y-3">
<div className="flex-1 rounded-lg bg-gray-50 px-6 pb-4 pt-8">
<h1 className={`${lusitana.className} mb-3 text-2xl`}>
Please log in to continue.
</h1>
<div className="w-full">
<div>
<label
className="mb-3 mt-5 block text-xs font-medium text-gray-900"
htmlFor="email"
>
Email
</label>
<div className="relative">
<input
className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500"
id="email"
type="email"
name="email"
placeholder="Enter your email address"
required
/>
<AtSymbolIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
</div>
<div className="mt-4">
<label
className="mb-3 mt-5 block text-xs font-medium text-gray-900"
htmlFor="password"
>
Password
</label>
<div className="relative">
<input
className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500"
id="password"
type="password"
name="password"
placeholder="Enter password"
required
minLength={6}
/>
<KeyIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
</div>
</div>
<Button className="mt-4 w-full">
Log in <ArrowRightIcon className="ml-auto h-5 w-5 text-gray-50" />
</Button>
<div className="flex h-8 items-end space-x-1">
{/* Add form errors here */}
</div>
</div>
</form>
);
}

View File

@ -1,3 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
'use client';
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';

5
app/ui/skeleton.tsx Normal file
View File

@ -0,0 +1,5 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
export default function Skeleton({ className }: { className: string }) {
return <div className={`bg-slate-200 motion-safe:animate-pulse rounded ${className}`} />;
}

View File

@ -0,0 +1,85 @@
---
- - :permit
- MIT
- :who:
:why:
:versions: []
:when: 2024-10-25 17:45:36.831184284 Z
- - :permit
- ISC
- :who:
:why:
:versions: []
:when: 2024-10-25 17:48:14.527140943 Z
- - :permit
- Apache 2.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:48:23.863998708 Z
- - :permit
- Simplified BSD
- :who:
:why:
:versions: []
:when: 2024-10-25 17:49:01.330574375 Z
- - :permit
- New BSD
- :who:
:why:
:versions: []
:when: 2024-10-25 17:49:53.995999923 Z
- - :permit
- LGPL-3.0-or-later
- :who:
:why:
:versions: []
:when: 2024-10-25 17:51:16.274818102 Z
- - :permit
- Python-2.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:51:32.610018037 Z
- - :permit
- BlueOak-1.0.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:52:28.568966565 Z
- - :permit
- BSD
- :who:
:why:
:versions: []
:when: 2024-10-25 17:52:37.235297087 Z
- - :permit
- The Unlicense
- :who:
:why:
:versions: []
:when: 2024-10-25 17:52:49.646463302 Z
- - :permit
- CC-BY-4.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:54:29.363007852 Z
- - :permit
- "(MIT AND Zlib)"
- :who:
:why:
:versions: []
:when: 2024-10-25 17:54:49.936741134 Z
- - :permit
- BSD Zero Clause License
- :who:
:why:
:versions: []
:when: 2024-10-25 17:55:31.968339009 Z
- - :permit
- Artistic-2.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:55:52.371898047 Z

View File

@ -8,30 +8,31 @@
"dependencies": {
"@heroicons/react": "^2.1.4",
"@tailwindcss/forms": "^0.5.7",
"@vercel/postgres": "^0.8.0",
"autoprefixer": "10.4.20",
"bcrypt": "^5.1.1",
"clsx": "^2.1.1",
"next": "15.0.0-canary.56",
"next-auth": "5.0.0-beta.20",
"postcss": "8.4.38",
"next": "15.1.4",
"next-auth": "5.0.0-beta.25",
"postcss": "8.5.1",
"primeicons": "^7.0.0",
"primereact": "^10.8.2",
"react": "19.0.0-rc-f38c22b244-20240704",
"react-dom": "19.0.0-rc-f38c22b244-20240704",
"tailwindcss": "3.4.9",
"typescript": "5.5.2",
"tailwindcss": "3.4.17",
"typescript": "5.7.3",
"use-debounce": "^10.0.1",
"uuid": "11.0.5",
"zod": "^3.23.8"
},
"devDependencies": {
"@playwright/test": "^1.46.0",
"@types/bcrypt": "^5.0.2",
"@types/node": "20.14.15",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0"
"@types/node": "22.10.7",
"@types/react": "18.3.18",
"@types/react-dom": "18.3.5"
},
"engines": {
"node": ">=20.12.0"
}
"node": ">=23.0.0"
},
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
}

822
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -1,7 +1,100 @@
import { test, expect } from '@playwright/test'
test('should navigate to the guests page', async ({ page }) => {
await page.goto('/dashboard/guests')
import { test, expect, Page } from '@playwright/test'
await expect(page.getByRole('heading', { name: 'Guests' })).toContainText('Guests')
})
const mockGuestsAPI = ({ page }: { page: Page }) => {
page.route('*/**/api/default/guests', async route => {
const json = [
{
"id": "f4a09c28-40ea-4553-90a5-96935a59cac6",
"status": "tentative",
"name": "Kristofer Rohan DVM",
"group": {
"id": "2fcb8b22-6b07-4c34-92e3-a2535dbc5b14",
"name": "Childhood friends",
}
},
{
"id": "bd585c40-0937-4cde-960a-bb23acfd6f18",
"status": "invited",
"name": "Olevia Quigley Jr.",
"group": {
"id": "da8edf26-3e1e-4cbb-b985-450c49fffe01",
"name": "Work",
}
},
];
await route.fulfill({ json })
})
}
const mockGroupsAPI = ({ page }: { page: Page }) => {
page.route('*/**/api/default/groups', async route => {
const json = [
{
"id": "ee44ffb9-1147-4842-a378-9eaeb0f0871a",
"name": "Pam's family",
"icon": "pi pi-users",
"parent_id": "cd9645e1-02c6-4fb9-bba6-1a960754b01c",
"color": "#ff0000",
"total": 3,
"considered": 2,
"invited": 1,
"confirmed": 0,
"declined": 0,
"tentative": 0
},
{
"id": "c8bda6ca-d8af-4bb8-b2bf-e6ec1c21b1e6",
"name": "Pam's work",
"icon": "pi pi-desktop",
"parent_id": "cd9645e1-02c6-4fb9-bba6-1a960754b01c",
"color": "#00ff00",
"total": 2,
"considered": 0,
"invited": 0,
"confirmed": 0,
"declined": 0,
"tentative": 2
},
];
await route.fulfill({ json })
})
}
test('should display the list of guests', async ({ page }) => {
await mockGuestsAPI({ page });
await page.goto('/default/dashboard/guests');
await expect(page.getByRole('tab', { name: 'Groups' })).toBeVisible();
await expect(page.getByRole('tab', { name: 'Guests' })).toBeVisible();
await expect(page.getByText('There are 2 elements in the list')).toBeVisible();
await expect(page.getByRole('row').nth(1).getByRole('cell', { name: 'Kristofer Rohan DVM' })).toBeVisible();
await expect(page.getByRole('row').nth(1).getByRole('cell', { name: 'Childhood friends' })).toBeVisible();
await expect(page.getByRole('row').nth(1).getByRole('cell', { name: 'Tentative' })).toBeVisible();
await expect(page.getByRole('row').nth(1).getByRole('button', { name: 'Confirm' })).toBeVisible();
await expect(page.getByRole('row').nth(1).getByRole('button', { name: 'Decline' })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('cell', { name: 'Olevia Quigley Jr.' })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('cell', { name: 'Work' })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('cell', { name: 'Invited' })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('button', { name: 'Confirm' })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('button', { name: 'Tentative' })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('button', { name: 'Decline' })).toBeVisible();
});
test('should display the list of groups', async ({ page }) => {
await mockGroupsAPI({ page });
await page.goto('/default/dashboard/guests');
await page.getByRole('tab', { name: 'Groups' }).click();
await expect(page.getByText('There are 2 elements in the list')).toBeVisible();
await expect(page.getByRole('row').nth(1).getByRole('cell', { name: "Pam's family" })).toBeVisible();
await expect(page.getByRole('row').nth(2).getByRole('cell', { name: "Pam's work" })).toBeVisible();
});