@tuturuuu/ui 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/biome.json +1 -1
- package/package.json +11 -11
- package/src/components/ui/calendar-app/components/calendar-connections.tsx +17 -13
- package/src/components/ui/calendar-app/components/connected-accounts-dialog.tsx +2 -5
- package/src/components/ui/calendar-app/components/use-calendar-connections-manager.ts +2 -5
- package/src/components/ui/calendar.test.tsx +24 -0
- package/src/components/ui/calendar.tsx +1 -0
- package/src/components/ui/currency-input.test.tsx +43 -0
- package/src/components/ui/currency-input.tsx +1 -1
- package/src/components/ui/custom/workspace-access/workspace-access-default-role-card.tsx +60 -35
- package/src/components/ui/custom/workspace-access/workspace-access-member-row.tsx +176 -167
- package/src/components/ui/custom/workspace-access/workspace-access-members.tsx +16 -10
- package/src/components/ui/custom/workspace-access/workspace-access-page-header.tsx +75 -36
- package/src/components/ui/custom/workspace-access/workspace-access-page.tsx +39 -42
- package/src/components/ui/custom/workspace-access/workspace-access-people-filters.tsx +1 -1
- package/src/components/ui/custom/workspace-access/workspace-access-roles.tsx +113 -91
- package/src/components/ui/custom/workspace-access/workspace-access-tabs-toolbar.tsx +73 -32
- package/src/components/ui/date-time-picker.tsx +352 -234
- package/src/components/ui/finance/categories-tags-tabs.tsx +23 -1
- package/src/components/ui/finance/command/finance-command-actions.test.tsx +48 -0
- package/src/components/ui/finance/command/finance-command-actions.tsx +200 -0
- package/src/components/ui/finance/command/finance-command-provider.test.tsx +151 -0
- package/src/components/ui/finance/command/finance-command-provider.tsx +250 -0
- package/src/components/ui/finance/command/finance-command-results.tsx +262 -0
- package/src/components/ui/finance/invoices/pending-invoices-table.tsx +22 -9
- package/src/components/ui/finance/shared/quick-actions.tsx +39 -90
- package/src/components/ui/finance/tags/tag-manager.tsx +24 -5
- package/src/components/ui/finance/transactions/form-basic-tab.tsx +33 -49
- package/src/components/ui/finance/transactions/form-types.ts +5 -0
- package/src/components/ui/finance/transactions/form.test.tsx +105 -22
- package/src/components/ui/finance/transactions/form.tsx +116 -20
- package/src/components/ui/finance/transactions/infinite-transactions-list.tsx +13 -6
- package/src/components/ui/finance/transactions/transaction-card.tsx +21 -9
- package/src/components/ui/finance/transactions/transaction-edit-dialog.test.tsx +25 -1
- package/src/components/ui/finance/transactions/transaction-edit-dialog.tsx +16 -3
- package/src/components/ui/finance/transactions/transactionId/transaction-details-client-page.tsx +3 -0
- package/src/components/ui/finance/transactions/transactionId/transaction-details-page.tsx +3 -0
- package/src/components/ui/finance/transactions/transactions-create-summary.tsx +6 -0
- package/src/components/ui/finance/transactions/transactions-infinite-page.tsx +20 -2
- package/src/components/ui/finance/transactions/transactions-page.tsx +4 -0
- package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-history-dialog.tsx +7 -2
- package/src/components/ui/finance/wallets/checkpoints/wallet-total-check-dialog.tsx +7 -2
- package/src/components/ui/finance/wallets/walletId/wallet-details-actions.test.tsx +38 -1
- package/src/components/ui/finance/wallets/walletId/wallet-details-actions.tsx +5 -0
- package/src/components/ui/finance/wallets/walletId/wallet-details-page.test.tsx +18 -2
- package/src/components/ui/finance/wallets/walletId/wallet-details-page.tsx +3 -0
- package/src/components/ui/finance/wallets/wallets-page.tsx +3 -0
- package/src/components/ui/legacy/calendar/settings/google-calendar-settings.tsx +2 -9
- package/src/components/ui/money-input.test.tsx +64 -0
- package/src/components/ui/money-input.tsx +63 -0
- package/src/components/ui/optional-time-picker.tsx +95 -0
- package/src/components/ui/quick-command-center.test.tsx +90 -0
- package/src/components/ui/quick-command-center.tsx +190 -0
- package/src/components/ui/storefront/cart-summary.tsx +126 -50
- package/src/components/ui/storefront/checkout-overlay.tsx +27 -0
- package/src/components/ui/storefront/hero-panel.tsx +23 -20
- package/src/components/ui/storefront/image-panel.tsx +6 -0
- package/src/components/ui/storefront/index.ts +11 -0
- package/src/components/ui/storefront/listing-card.tsx +84 -22
- package/src/components/ui/storefront/product-detail.tsx +289 -0
- package/src/components/ui/storefront/product-dialog.tsx +72 -0
- package/src/components/ui/storefront/storefront-surface.test.tsx +132 -5
- package/src/components/ui/storefront/storefront-surface.tsx +371 -128
- package/src/components/ui/storefront/types.ts +25 -1
- package/src/components/ui/storefront/utils.ts +118 -13
- package/src/components/ui/text-editor/__tests__/content-migration.test.ts +32 -0
- package/src/components/ui/text-editor/__tests__/image-extension.test.ts +69 -1
- package/src/components/ui/text-editor/__tests__/video-extension.test.ts +47 -0
- package/src/components/ui/text-editor/content-migration.ts +41 -18
- package/src/components/ui/text-editor/extensions.ts +1 -1
- package/src/components/ui/text-editor/image-extension.ts +40 -18
- package/src/components/ui/text-editor/video-extension.ts +11 -2
- package/src/components/ui/tu-do/boards/__tests__/workspace-projects-client-page.test.tsx +70 -1
- package/src/components/ui/tu-do/boards/boardId/board-column-external-retry.test.tsx +127 -0
- package/src/components/ui/tu-do/boards/boardId/board-column.tsx +1 -3
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-cache.ts +13 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.test.ts +63 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.ts +46 -8
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.test.tsx +13 -2
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.tsx +3 -1
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.test.tsx +164 -0
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.tsx +56 -2
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-display.ts +9 -0
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-grid.tsx +8 -16
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-task-row.tsx +5 -25
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-utils.test.ts +36 -1
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-utils.ts +51 -2
- package/src/components/ui/tu-do/boards/workspace-projects-client-page.tsx +13 -3
- package/src/components/ui/tu-do/shared/__tests__/board-views.test.tsx +34 -1
- package/src/components/ui/tu-do/shared/board-header.tsx +39 -0
- package/src/components/ui/tu-do/shared/board-views.tsx +9 -7
- package/src/components/ui/tu-do/shared/cursor-overlay-multi-wrapper.tsx +53 -12
- package/src/components/ui/tu-do/shared/task-dialog-presentation.test.ts +53 -0
- package/src/components/ui/tu-do/shared/task-dialog-presentation.ts +19 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.test.tsx +57 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.tsx +136 -111
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-description-editor.tsx +3 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/task-api.test.ts +171 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/task-api.ts +200 -36
- package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-save.ts +21 -2
- package/src/components/ui/tu-do/shared/task-edit-dialog.tsx +42 -14
- package/src/hooks/__tests__/useBoardRealtime.test.tsx +2 -2
- package/src/hooks/__tests__/useCursorTracking.test.tsx +212 -0
- package/src/hooks/useBoardRealtime.ts +6 -3
- package/src/hooks/useBoardRealtime.types.ts +11 -0
- package/src/hooks/useCursorTracking.ts +91 -27
- package/src/hooks/useTaskUserRealtime.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.0](https://github.com/tutur3u/platform/compare/ui-v0.7.0...ui-v0.8.0) (2026-06-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **inventory:** fix Polar checkout currency, add 2-way product sync, cache + redesign storefront ([de2f6fd](https://github.com/tutur3u/platform/commit/de2f6fd6e06ce5242a150a35d3989798f52b9ee9))
|
|
9
|
+
* **inventory:** per-variant SKUs + storefront cart, dialog & instant checkout ([9662b85](https://github.com/tutur3u/platform/commit/9662b8501bcab51033edde79b44991c8ba648a37))
|
|
10
|
+
* **inventory:** store commerce money in minor units and harden Polar sync ([3f7ee1d](https://github.com/tutur3u/platform/commit/3f7ee1da9335732854037e7e79fca9d5d2a381d0))
|
|
11
|
+
* **storefront-ui:** dedicated product page, richer cart, loading skeleton ([d4a67f8](https://github.com/tutur3u/platform/commit/d4a67f8e6097d51aab6ca983245529725fcaba5c))
|
|
12
|
+
* **storefront-ui:** polish checkout layout and order-status page ([ead94ed](https://github.com/tutur3u/platform/commit/ead94edaa2ac6e79f9e56fd9f48d7a098487f2de))
|
|
13
|
+
* **storefront:** dedicated checkout page with buyer details + order-placed success ([258014d](https://github.com/tutur3u/platform/commit/258014d642e7cf99164e92fec44cd32114ecf68d))
|
|
14
|
+
* **storefront:** make the storefront accent color visibly prominent ([f2b5289](https://github.com/tutur3u/platform/commit/f2b5289506fd8e289f4bfb2bb6755cbc10ea2430))
|
|
15
|
+
* **storefront:** polish checkout cart experience ([cfdccfa](https://github.com/tutur3u/platform/commit/cfdccfa089703d9dde4357eeef8e52c00ccf6d4b))
|
|
16
|
+
* **tasks:** add per-board default list for new tasks ([2d1d308](https://github.com/tutur3u/platform/commit/2d1d3082422bdd4813accb258fee79b322ce647b))
|
|
17
|
+
* **web:** consolidate workspace roles into members and redesign access UI ([4a16407](https://github.com/tutur3u/platform/commit/4a164070e1fe020a834ce4fe77ff4ae371e4e366))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **ci:** format storefront files and harden upstash scan wrapper ([4c82444](https://github.com/tutur3u/platform/commit/4c824446725dc280edde3e54f946bf386a52952d))
|
|
23
|
+
* **ci:** sort tailwind classes in storefront product-detail (biome lint) ([809c3b9](https://github.com/tutur3u/platform/commit/809c3b9b1e514fb218b58941c9542c75bd723f2d))
|
|
24
|
+
* **deps:** keep lodash on latest reviewed artifact ([19909b3](https://github.com/tutur3u/platform/commit/19909b334581d3b58cdcd19e9b2fde553f7ad60a))
|
|
25
|
+
* **deps:** pin reviewed lodash artifact ([dfcf585](https://github.com/tutur3u/platform/commit/dfcf585fab9cc0b425cac5d60c5bccc997340be5))
|
|
26
|
+
* **editor:** clear stale upload handlers ([ed34408](https://github.com/tutur3u/platform/commit/ed34408e9e48ee13bf7e69c2a8ba222d75c67253))
|
|
27
|
+
* **epm:** validate summary editor content ([bd87c77](https://github.com/tutur3u/platform/commit/bd87c770690c75a125fe2a727f3ad39aa925b5fd))
|
|
28
|
+
* **finance:** harden transaction enrichment ([eddd93b](https://github.com/tutur3u/platform/commit/eddd93bd11fb451a7fa5da2e4ab2892fad931ab5))
|
|
29
|
+
* **inventory:** block unsafe storefront section links ([870ce76](https://github.com/tutur3u/platform/commit/870ce760237f43ca2a3d1221359c4a06d1bc7653))
|
|
30
|
+
* **storefront-ui:** prevent horizontal overflow and cap cart height ([5825c49](https://github.com/tutur3u/platform/commit/5825c49fb9b77c859cda4ec6bbb6ba382925e519))
|
|
31
|
+
* **storefront-ui:** show an empty-cart state instead of "no listings" in the cart ([00bdb40](https://github.com/tutur3u/platform/commit/00bdb40eb344b17c3727fda1ea0c042508c63901))
|
|
32
|
+
* **tasks:** authorize board page before workspace ([9b1f740](https://github.com/tutur3u/platform/commit/9b1f74096a4a889b7733b6ffe37d4d16f442d974))
|
|
33
|
+
* **tasks:** cap timeline rendering work ([f2722ee](https://github.com/tutur3u/platform/commit/f2722ee0c3778153e1b014280bc1513305c5be7a))
|
|
34
|
+
* **tasks:** gate boards data access ([6daf363](https://github.com/tutur3u/platform/commit/6daf363b1c73593a233371a6cf079a3a4a015daa))
|
|
35
|
+
* **tasks:** ignore stale drag rollbacks ([c60131f](https://github.com/tutur3u/platform/commit/c60131f9f0930c81d3d2ccc6f2f9e918968d4b77))
|
|
36
|
+
* **tasks:** refine document task dialog presentation ([ca10735](https://github.com/tutur3u/platform/commit/ca10735f086a24be065eded03b8bc6e9382e2c5f))
|
|
37
|
+
* **tasks:** secure cursor realtime channels ([a0ec120](https://github.com/tutur3u/platform/commit/a0ec120d912b7998fe43c90b675a09d0d3798dfe))
|
|
38
|
+
* **tasks:** secure realtime task channels ([6d98d16](https://github.com/tutur3u/platform/commit/6d98d16baa9ecf68bdd47ce3ce6dc1ff2e2bca84))
|
|
39
|
+
* **tasks:** secure realtime task channels ([03dc6d6](https://github.com/tutur3u/platform/commit/03dc6d66666d1d3ae422f91cb94285367a8c1071))
|
|
40
|
+
* **tasks:** stop external lane retry loops ([713c327](https://github.com/tutur3u/platform/commit/713c327a613b018e72e376c03324517c6ee673c3))
|
|
41
|
+
* **tu-do:** center compact task edit dialog instead of anchoring to bottom ([67f38aa](https://github.com/tutur3u/platform/commit/67f38aaab1eab4b5340dfe049eed9c1e224c83b1))
|
|
42
|
+
* **tu-do:** preserve newlines and dim compact description preview ([ee01f40](https://github.com/tutur3u/platform/commit/ee01f40ab5ae800bf8aa1c59f19eb4f2bd69c256))
|
|
43
|
+
* **ui:** keep locale decimals in currency input ([3cd2420](https://github.com/tutur3u/platform/commit/3cd242026c3afe51eedabc3ec070093d0a94523f))
|
|
44
|
+
* **web:** stop new-workspace setup from trapping users on "Preparing Workspace" ([3f7ee1d](https://github.com/tutur3u/platform/commit/3f7ee1da9335732854037e7e79fca9d5d2a381d0))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Performance Improvements
|
|
48
|
+
|
|
49
|
+
* **storefront-ui:** lazy-load product images, eager-load above-the-fold ([6da600e](https://github.com/tutur3u/platform/commit/6da600eec0ce964ac61ae7890cf4574ada6aef3e))
|
|
50
|
+
|
|
51
|
+
## [0.7.0](https://github.com/tutur3u/platform/compare/ui-v0.6.2...ui-v0.7.0) (2026-06-15)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### Features
|
|
55
|
+
|
|
56
|
+
* **finance:** add command center shortcuts ([d0197f7](https://github.com/tutur3u/platform/commit/d0197f705227cdf8171704b40119b66b1140be80))
|
|
57
|
+
* **inventory:** field tooltips, tabbed dialogs, row-click edit, storefront polish ([e27d7bb](https://github.com/tutur3u/platform/commit/e27d7bbd75a76b8e6d9395faaa48ad6b465dca4b))
|
|
58
|
+
* **inventory:** upgrade storefront commerce ([ac43942](https://github.com/tutur3u/platform/commit/ac439426ec6d7abc25efbf7ef88468e32be3a46e))
|
|
59
|
+
* **ui:** add optional time picker ([d4cf439](https://github.com/tutur3u/platform/commit/d4cf4398c8efd8ca5267b770e07f1015a59d43fd))
|
|
60
|
+
* **ui:** redesign optional time picker ([cadbf12](https://github.com/tutur3u/platform/commit/cadbf124a9048d85164082eec2b857feb78b1070))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### Bug Fixes
|
|
64
|
+
|
|
65
|
+
* **calendar:** preserve Google OAuth refresh tokens ([4358623](https://github.com/tutur3u/platform/commit/4358623a2dbde76fd84af59bb18e540994a5d091))
|
|
66
|
+
* **finance:** stop pending invoices from intermittently failing to load ([c4a51b8](https://github.com/tutur3u/platform/commit/c4a51b89e3cad8130b8016864cf25f4da6db6fc1))
|
|
67
|
+
* **tasks:** persist large task descriptions in chunks ([457744a](https://github.com/tutur3u/platform/commit/457744aa051d06baccc5df5aa4d4cb509534ea8b))
|
|
68
|
+
|
|
3
69
|
## [0.6.2](https://github.com/tutur3u/platform/compare/ui-v0.6.1...ui-v0.6.2) (2026-06-13)
|
|
4
70
|
|
|
5
71
|
|
package/biome.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuturuuu/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -83,12 +83,12 @@
|
|
|
83
83
|
"@tiptap/react": "3.26.1",
|
|
84
84
|
"@tiptap/starter-kit": "3.26.1",
|
|
85
85
|
"@tuturuuu/ai": "0.2.2",
|
|
86
|
-
"@tuturuuu/apis": "0.
|
|
86
|
+
"@tuturuuu/apis": "0.5.0",
|
|
87
87
|
"@tuturuuu/hooks": "0.0.2",
|
|
88
88
|
"@tuturuuu/icons": "0.0.6",
|
|
89
|
-
"@tuturuuu/internal-api": "0.
|
|
90
|
-
"@tuturuuu/supabase": "0.3.
|
|
91
|
-
"@tuturuuu/utils": "0.
|
|
89
|
+
"@tuturuuu/internal-api": "0.9.0",
|
|
90
|
+
"@tuturuuu/supabase": "0.3.4",
|
|
91
|
+
"@tuturuuu/utils": "0.8.0",
|
|
92
92
|
"@types/debug": "^4.1.13",
|
|
93
93
|
"browser-image-compression": "^2.0.2",
|
|
94
94
|
"class-variance-authority": "^0.7.1",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"html2canvas-pro": "^2.0.2",
|
|
106
106
|
"input-otp": "^1.4.2",
|
|
107
107
|
"katex": "^0.17.0",
|
|
108
|
-
"lodash": "
|
|
108
|
+
"lodash": "4.18.1",
|
|
109
109
|
"moment": "^2.30.1",
|
|
110
110
|
"motion": "^12.40.0",
|
|
111
111
|
"next": "^16.2.9",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"react-day-picker": "^10.0.1",
|
|
120
120
|
"react-dom": "^19.2.7",
|
|
121
121
|
"react-dropzone": "^15.0.0",
|
|
122
|
-
"react-hook-form": "^7.
|
|
122
|
+
"react-hook-form": "^7.79.0",
|
|
123
123
|
"react-markdown": "^10.1.0",
|
|
124
124
|
"react-papaparse": "^4.4.0",
|
|
125
125
|
"react-pdf": "^10.4.1",
|
|
@@ -135,19 +135,19 @@
|
|
|
135
135
|
"tiptap-extension-resize-image": "^1.4.3",
|
|
136
136
|
"use-debounce": "^10.1.1",
|
|
137
137
|
"vaul": "^1.1.2",
|
|
138
|
-
"xlsx": "
|
|
138
|
+
"xlsx": "file:vendor/xlsx-0.20.3.tgz",
|
|
139
139
|
"y-protocols": "^1.0.7",
|
|
140
140
|
"yjs": "^13.6.31",
|
|
141
141
|
"zod": "^4.4.3"
|
|
142
142
|
},
|
|
143
143
|
"devDependencies": {
|
|
144
|
-
"@tailwindcss/postcss": "^4.3.
|
|
144
|
+
"@tailwindcss/postcss": "^4.3.1",
|
|
145
145
|
"@tailwindcss/typography": "^0.5.20",
|
|
146
146
|
"@tanstack/react-query": "^5.101.0",
|
|
147
147
|
"@tanstack/react-table": "^8.21.3",
|
|
148
148
|
"@testing-library/jest-dom": "^6.9.1",
|
|
149
149
|
"@testing-library/react": "^16.3.2",
|
|
150
|
-
"@tuturuuu/types": "0.
|
|
150
|
+
"@tuturuuu/types": "0.10.0",
|
|
151
151
|
"@tuturuuu/typescript-config": "0.1.1",
|
|
152
152
|
"@types/html2canvas": "^1.0.0",
|
|
153
153
|
"@types/lodash": "^4.17.24",
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"jsdom": "^29.1.1",
|
|
163
163
|
"postcss": "^8.5.14",
|
|
164
164
|
"postcss-load-config": "^6.0.1",
|
|
165
|
-
"tailwindcss": "^4.3.
|
|
165
|
+
"tailwindcss": "^4.3.1",
|
|
166
166
|
"typescript": "^6.0.3",
|
|
167
167
|
"uuid": "^14.0.0",
|
|
168
168
|
"vitest": "^4.1.8"
|
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
Trash2,
|
|
16
16
|
Upload,
|
|
17
17
|
} from '@tuturuuu/icons';
|
|
18
|
+
import {
|
|
19
|
+
getGoogleCalendarAuthUrl,
|
|
20
|
+
InternalApiError,
|
|
21
|
+
} from '@tuturuuu/internal-api';
|
|
18
22
|
import { useTranslations } from 'next-intl';
|
|
19
23
|
import { useMemo, useState } from 'react';
|
|
20
24
|
import { useCalendarSync } from '../../../../hooks/use-calendar-sync';
|
|
@@ -292,21 +296,21 @@ export default function CalendarConnections({
|
|
|
292
296
|
const googleAuthMutation = useMutation<AuthResponse, Error, void>({
|
|
293
297
|
mutationKey: ['calendar', 'google-auth', wsId],
|
|
294
298
|
mutationFn: async () => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
})
|
|
299
|
+
try {
|
|
300
|
+
return await getGoogleCalendarAuthUrl(wsId);
|
|
301
|
+
} catch (error) {
|
|
302
|
+
if (error instanceof InternalApiError) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
error.status === 401
|
|
305
|
+
? 'unauthorized'
|
|
306
|
+
: error.status === 403
|
|
307
|
+
? 'forbidden'
|
|
308
|
+
: 'unknown_error'
|
|
309
|
+
);
|
|
310
|
+
}
|
|
298
311
|
|
|
299
|
-
|
|
300
|
-
throw new Error(
|
|
301
|
-
response.status === 401
|
|
302
|
-
? 'unauthorized'
|
|
303
|
-
: response.status === 403
|
|
304
|
-
? 'forbidden'
|
|
305
|
-
: 'unknown_error'
|
|
306
|
-
);
|
|
312
|
+
throw error;
|
|
307
313
|
}
|
|
308
|
-
|
|
309
|
-
return (await response.json()) as AuthResponse;
|
|
310
314
|
},
|
|
311
315
|
onSuccess: (data) => {
|
|
312
316
|
const { authUrl } = data;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
4
4
|
import { AlertCircle, Loader2, Plus, Trash2, User } from '@tuturuuu/icons';
|
|
5
|
+
import { getGoogleCalendarAuthUrl } from '@tuturuuu/internal-api';
|
|
5
6
|
import Image from 'next/image';
|
|
6
7
|
import { useTranslations } from 'next-intl';
|
|
7
8
|
import React, { useState } from 'react';
|
|
@@ -137,11 +138,7 @@ export function ConnectedAccountsDialog({
|
|
|
137
138
|
// Google auth mutation
|
|
138
139
|
const googleAuthMutation = useMutation<AuthResponse, Error, void>({
|
|
139
140
|
mutationKey: ['calendar', 'google-auth', wsId],
|
|
140
|
-
mutationFn:
|
|
141
|
-
const response = await fetch(`/api/v1/calendar/auth?wsId=${wsId}`);
|
|
142
|
-
if (!response.ok) throw new Error('Failed to get auth URL');
|
|
143
|
-
return response.json();
|
|
144
|
-
},
|
|
141
|
+
mutationFn: () => getGoogleCalendarAuthUrl(wsId),
|
|
145
142
|
onSuccess: (data) => {
|
|
146
143
|
if (data.authUrl) {
|
|
147
144
|
window.location.href = data.authUrl;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
2
|
import {
|
|
3
3
|
type CalendarSourceOption,
|
|
4
|
+
getGoogleCalendarAuthUrl,
|
|
4
5
|
getWorkspaceCalendarDefaultSource,
|
|
5
6
|
updateWorkspaceCalendarDefaultSource,
|
|
6
7
|
} from '@tuturuuu/internal-api';
|
|
@@ -392,11 +393,7 @@ export function useCalendarConnectionsManager(wsId: string) {
|
|
|
392
393
|
// Google auth mutation
|
|
393
394
|
const googleAuthMutation = useMutation<AuthResponse, Error, void>({
|
|
394
395
|
mutationKey: ['calendar', 'google-auth', wsId],
|
|
395
|
-
mutationFn:
|
|
396
|
-
const response = await fetch(`/api/v1/calendar/auth?wsId=${wsId}`);
|
|
397
|
-
if (!response.ok) throw new Error('Failed to get auth URL');
|
|
398
|
-
return response.json();
|
|
399
|
-
},
|
|
396
|
+
mutationFn: () => getGoogleCalendarAuthUrl(wsId),
|
|
400
397
|
onSuccess: (data) => {
|
|
401
398
|
if (data.authUrl) window.location.href = data.authUrl;
|
|
402
399
|
else toast.error(t('auth_url_invalid'));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { Calendar } from './calendar';
|
|
4
|
+
|
|
5
|
+
vi.mock('react-day-picker', () => ({
|
|
6
|
+
DayPicker: ({ fixedWeeks }: { fixedWeeks?: boolean }) => (
|
|
7
|
+
<div data-fixed-weeks={String(fixedWeeks)} data-testid="day-picker" />
|
|
8
|
+
),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock('../../hooks/use-calendar-preferences', () => ({
|
|
12
|
+
useCalendarPreferences: () => ({ weekStartsOn: 1 }),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
describe('Calendar', () => {
|
|
16
|
+
it('renders DayPicker with fixed weeks to avoid layout shift', () => {
|
|
17
|
+
render(<Calendar mode="single" />);
|
|
18
|
+
|
|
19
|
+
expect(screen.getByTestId('day-picker')).toHaveAttribute(
|
|
20
|
+
'data-fixed-weeks',
|
|
21
|
+
'true'
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -311,6 +311,7 @@ function Calendar({
|
|
|
311
311
|
onMonthChange={setMonth}
|
|
312
312
|
defaultMonth={initialMonth}
|
|
313
313
|
showOutsideDays={true}
|
|
314
|
+
fixedWeeks={true}
|
|
314
315
|
weekStartsOn={props.weekStartsOn ?? preferences.weekStartsOn}
|
|
315
316
|
className={cn('', className)}
|
|
316
317
|
classNames={normalizeClassNames({
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { CurrencyInput } from './currency-input';
|
|
4
|
+
|
|
5
|
+
describe('CurrencyInput', () => {
|
|
6
|
+
it('keeps locale decimal separators while editing', () => {
|
|
7
|
+
const onChange = vi.fn();
|
|
8
|
+
|
|
9
|
+
render(
|
|
10
|
+
<CurrencyInput
|
|
11
|
+
aria-label="Amount"
|
|
12
|
+
hideHelpers
|
|
13
|
+
locale="vi-VN"
|
|
14
|
+
maximumFractionDigits={2}
|
|
15
|
+
onChange={onChange}
|
|
16
|
+
value={undefined}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const input = screen.getByLabelText('Amount') as HTMLInputElement;
|
|
21
|
+
|
|
22
|
+
fireEvent.focus(input);
|
|
23
|
+
fireEvent.change(input, {
|
|
24
|
+
target: {
|
|
25
|
+
selectionStart: 3,
|
|
26
|
+
value: '1,2',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(input).toHaveValue('1,2');
|
|
31
|
+
expect(onChange).toHaveBeenLastCalledWith(1.2);
|
|
32
|
+
|
|
33
|
+
fireEvent.change(input, {
|
|
34
|
+
target: {
|
|
35
|
+
selectionStart: input.value.length + 1,
|
|
36
|
+
value: `${input.value}3`,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(input).toHaveValue('1,23');
|
|
41
|
+
expect(onChange).toHaveBeenLastCalledWith(1.23);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -197,7 +197,7 @@ export const CurrencyInput = forwardRef<HTMLInputElement, CurrencyInputProps>(
|
|
|
197
197
|
// Build final formatted string
|
|
198
198
|
let formatted = formattedInteger;
|
|
199
199
|
if (hasDecimal) {
|
|
200
|
-
formatted +=
|
|
200
|
+
formatted += `${localeSeparators.decimal}${decimalPart}`;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
// Calculate new cursor position
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { Pencil } from '@tuturuuu/icons';
|
|
3
|
+
import { KeyRound, Pencil, ShieldUser } from '@tuturuuu/icons';
|
|
4
4
|
import type { WorkspaceDefaultPermissionMemberType } from '@tuturuuu/types';
|
|
5
5
|
import { Button } from '@tuturuuu/ui/button';
|
|
6
|
-
import {
|
|
7
|
-
Card,
|
|
8
|
-
CardContent,
|
|
9
|
-
CardDescription,
|
|
10
|
-
CardHeader,
|
|
11
|
-
CardTitle,
|
|
12
|
-
} from '@tuturuuu/ui/card';
|
|
13
6
|
import { Skeleton } from '@tuturuuu/ui/skeleton';
|
|
14
7
|
import { useTranslations } from 'next-intl';
|
|
15
8
|
import type { WorkspaceAccessRole } from './types';
|
|
@@ -37,45 +30,77 @@ export function WorkspaceAccessDefaultRoleCard({
|
|
|
37
30
|
}) {
|
|
38
31
|
const t = useTranslations() as (key: string) => string;
|
|
39
32
|
const isGuest = memberType === 'GUEST';
|
|
33
|
+
const enabled = enabledPermissionCount(role);
|
|
34
|
+
const pct =
|
|
35
|
+
permissionCount > 0 ? Math.round((enabled / permissionCount) * 100) : 0;
|
|
36
|
+
const accent = isGuest
|
|
37
|
+
? 'border-dynamic-blue/30 bg-dynamic-blue/10 text-dynamic-blue'
|
|
38
|
+
: 'border-dynamic-green/30 bg-dynamic-green/10 text-dynamic-green';
|
|
39
|
+
const barColor = isGuest ? 'bg-dynamic-blue' : 'bg-dynamic-green';
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
|
-
<
|
|
43
|
-
<
|
|
44
|
-
<div className="flex
|
|
45
|
-
<div
|
|
46
|
-
|
|
42
|
+
<div className="rounded-xl border border-border bg-background p-5">
|
|
43
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
44
|
+
<div className="flex min-w-0 gap-3">
|
|
45
|
+
<div
|
|
46
|
+
className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border ${accent}`}
|
|
47
|
+
>
|
|
48
|
+
{isGuest ? (
|
|
49
|
+
<KeyRound className="h-5 w-5" />
|
|
50
|
+
) : (
|
|
51
|
+
<ShieldUser className="h-5 w-5" />
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
<div className="min-w-0">
|
|
55
|
+
<div className="font-semibold text-base">
|
|
47
56
|
{isGuest
|
|
48
57
|
? t('ws-roles.guest_defaults')
|
|
49
58
|
: t('ws-roles.member_defaults')}
|
|
50
|
-
</
|
|
51
|
-
<
|
|
59
|
+
</div>
|
|
60
|
+
<p className="mt-0.5 max-w-md text-muted-foreground text-sm">
|
|
52
61
|
{isGuest
|
|
53
62
|
? t('ws-roles.guest_defaults_description')
|
|
54
63
|
: t('ws-roles.member_defaults_description')}
|
|
55
|
-
</
|
|
64
|
+
</p>
|
|
56
65
|
</div>
|
|
57
|
-
{canManageRoles ? (
|
|
58
|
-
<Button
|
|
59
|
-
variant="outline"
|
|
60
|
-
size="sm"
|
|
61
|
-
onClick={() => onEdit(memberType)}
|
|
62
|
-
>
|
|
63
|
-
<Pencil className="mr-2 h-4 w-4" />
|
|
64
|
-
{t('common.edit')}
|
|
65
|
-
</Button>
|
|
66
|
-
) : null}
|
|
67
66
|
</div>
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
{canManageRoles ? (
|
|
68
|
+
<Button
|
|
69
|
+
variant="outline"
|
|
70
|
+
size="sm"
|
|
71
|
+
onClick={() => onEdit(memberType)}
|
|
72
|
+
>
|
|
73
|
+
<Pencil className="mr-2 h-4 w-4" />
|
|
74
|
+
{t('common.edit')}
|
|
75
|
+
</Button>
|
|
76
|
+
) : null}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div className="mt-4 space-y-3">
|
|
70
80
|
{isLoading ? (
|
|
71
81
|
<Skeleton className="h-24 rounded-lg" />
|
|
72
82
|
) : (
|
|
73
83
|
<>
|
|
74
|
-
<div
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
<div>
|
|
85
|
+
<div className="flex items-baseline justify-between gap-1.5">
|
|
86
|
+
<div className="flex items-baseline gap-1.5">
|
|
87
|
+
<span className="font-bold text-2xl tabular-nums">
|
|
88
|
+
{enabled}
|
|
89
|
+
</span>
|
|
90
|
+
<span className="text-base text-muted-foreground">
|
|
91
|
+
/ {permissionCount}
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
94
|
+
<span className="text-muted-foreground text-sm">
|
|
95
|
+
{t('ws-roles.permissions')}
|
|
96
|
+
</span>
|
|
97
|
+
</div>
|
|
98
|
+
<div className="mt-2 h-1.5 max-w-md overflow-hidden rounded-full bg-foreground/10">
|
|
99
|
+
<div
|
|
100
|
+
className={`h-full rounded-full ${barColor}`}
|
|
101
|
+
style={{ width: `${pct}%` }}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
79
104
|
</div>
|
|
80
105
|
<div className="flex flex-wrap gap-2">
|
|
81
106
|
<WorkspaceAccessPermissionPreview
|
|
@@ -86,7 +111,7 @@ export function WorkspaceAccessDefaultRoleCard({
|
|
|
86
111
|
</div>
|
|
87
112
|
</>
|
|
88
113
|
)}
|
|
89
|
-
</
|
|
90
|
-
</
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
91
116
|
);
|
|
92
117
|
}
|