@getmicdrop/svelte-components 5.3.12 → 5.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/calendar/AboutShow/AboutShow.svelte +172 -172
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +782 -782
- package/dist/calendar/FAQs/FAQs.svelte +75 -75
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +126 -126
- package/dist/calendar/OrderSummary/OrderSummary.svelte +367 -367
- package/dist/calendar/PublicCard/PublicCard.svelte +145 -145
- package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
- package/dist/components/Layout/Grid.svelte +109 -109
- package/dist/components/Layout/Section.svelte +80 -80
- package/dist/components/Layout/Sidebar.svelte +108 -108
- package/dist/components/Layout/Stack.svelte +90 -90
- package/dist/constants/formOptions.js +26 -26
- package/dist/constants/validation.js +91 -91
- package/dist/constants/validation.spec.js +64 -64
- package/dist/datetime/__tests__/format.test.d.ts +2 -0
- package/dist/datetime/__tests__/format.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/format.test.js +268 -0
- package/dist/datetime/__tests__/integration.test.d.ts +2 -0
- package/dist/datetime/__tests__/integration.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/integration.test.js +243 -0
- package/dist/datetime/__tests__/parse.test.d.ts +2 -0
- package/dist/datetime/__tests__/parse.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/parse.test.js +261 -0
- package/dist/datetime/__tests__/timezone.test.d.ts +2 -0
- package/dist/datetime/__tests__/timezone.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/timezone.test.js +214 -0
- package/dist/datetime/constants.d.ts +133 -0
- package/dist/datetime/constants.d.ts.map +1 -0
- package/dist/datetime/constants.js +112 -0
- package/dist/datetime/format.d.ts +158 -0
- package/dist/datetime/format.d.ts.map +1 -0
- package/dist/datetime/format.js +315 -0
- package/dist/datetime/index.d.ts +42 -0
- package/dist/datetime/index.d.ts.map +1 -0
- package/dist/datetime/index.js +44 -0
- package/dist/datetime/parse.d.ts +149 -0
- package/dist/datetime/parse.d.ts.map +1 -0
- package/dist/datetime/parse.js +276 -0
- package/dist/datetime/timezone.d.ts +95 -0
- package/dist/datetime/timezone.d.ts.map +1 -0
- package/dist/datetime/timezone.js +241 -0
- package/dist/datetime/types.d.ts +105 -0
- package/dist/datetime/types.d.ts.map +1 -0
- package/dist/datetime/types.js +31 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +232 -218
- package/dist/patterns/data/DataGrid.svelte +45 -45
- package/dist/patterns/data/DataList.svelte +24 -24
- package/dist/patterns/data/DataTable.svelte +40 -40
- package/dist/patterns/forms/FormActions.spec.js +88 -88
- package/dist/patterns/forms/FormActions.stories.svelte +97 -97
- package/dist/patterns/forms/FormActions.svelte +46 -46
- package/dist/patterns/forms/FormGrid.svelte +33 -33
- package/dist/patterns/forms/FormSection.svelte +32 -32
- package/dist/patterns/forms/FormValidationSummary.spec.js +203 -203
- package/dist/patterns/forms/FormValidationSummary.stories.svelte +97 -97
- package/dist/patterns/forms/FormValidationSummary.svelte +67 -67
- package/dist/patterns/layout/Grid.svelte +35 -35
- package/dist/patterns/layout/Sidebar.svelte +39 -39
- package/dist/patterns/layout/Stack.svelte +45 -45
- package/dist/patterns/navigation/BottomNav.spec.js +130 -130
- package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
- package/dist/patterns/navigation/BottomNav.svelte +54 -54
- package/dist/patterns/navigation/Header.spec.js +203 -203
- package/dist/patterns/navigation/Header.stories.svelte +77 -77
- package/dist/patterns/navigation/Header.svelte +240 -240
- package/dist/patterns/page/PageHeader.svelte +36 -36
- package/dist/patterns/page/PageLayout.svelte +40 -40
- package/dist/patterns/page/PageLoader.spec.js +54 -54
- package/dist/patterns/page/PageLoader.stories.svelte +137 -137
- package/dist/patterns/page/PageLoader.svelte +41 -41
- package/dist/patterns/page/SectionHeader.svelte +41 -41
- package/dist/presets/badges.js +112 -112
- package/dist/presets/buttons.js +76 -76
- package/dist/presets/index.js +9 -9
- package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
- package/dist/primitives/Accordion/Accordion.svelte +61 -61
- package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
- package/dist/primitives/Alert/Alert.spec.js +170 -170
- package/dist/primitives/Alert/Alert.stories.svelte +88 -88
- package/dist/primitives/Alert/Alert.svelte +65 -65
- package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
- package/dist/primitives/Avatar/Avatar.svelte +66 -66
- package/dist/primitives/Badges/Badge.spec.js +103 -103
- package/dist/primitives/Badges/Badge.stories.svelte +86 -86
- package/dist/primitives/Badges/Badge.svelte +142 -142
- package/dist/primitives/BottomSheet/BottomSheet.spec.js +127 -127
- package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
- package/dist/primitives/BottomSheet/BottomSheet.svelte +100 -100
- package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +120 -120
- package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +89 -89
- package/dist/primitives/Button/Button.spec.js +211 -211
- package/dist/primitives/Button/Button.stories.svelte +76 -76
- package/dist/primitives/Button/Button.svelte +301 -301
- package/dist/primitives/Button/ButtonSaveDemo.spec.js +48 -48
- package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
- package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
- package/dist/primitives/Card.spec.js +49 -49
- package/dist/primitives/Card.stories.svelte +22 -22
- package/dist/primitives/Card.svelte +28 -28
- package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
- package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
- package/dist/primitives/DarkModeToggle.spec.js +357 -357
- package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
- package/dist/primitives/DarkModeToggle.svelte +136 -136
- package/dist/primitives/Drawer/Drawer.stories.svelte +100 -100
- package/dist/primitives/Drawer/Drawer.svelte +214 -214
- package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
- package/dist/primitives/Dropdown/Dropdown.svelte +148 -148
- package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
- package/dist/primitives/Icons/ArrowLeft.svelte +20 -20
- package/dist/primitives/Icons/ArrowRight.svelte +20 -20
- package/dist/primitives/Icons/Availability.svelte +26 -26
- package/dist/primitives/Icons/Back.svelte +26 -26
- package/dist/primitives/Icons/CheckCircle.svelte +18 -18
- package/dist/primitives/Icons/CheckCircleOutline.svelte +27 -27
- package/dist/primitives/Icons/ChevronLeft.svelte +16 -16
- package/dist/primitives/Icons/ChevronRight.svelte +16 -16
- package/dist/primitives/Icons/Copy.svelte +27 -27
- package/dist/primitives/Icons/Cross.svelte +17 -17
- package/dist/primitives/Icons/DownArrow.svelte +20 -20
- package/dist/primitives/Icons/ErrorCircle.svelte +18 -18
- package/dist/primitives/Icons/FacebookIcon.svelte +13 -13
- package/dist/primitives/Icons/Home.svelte +27 -27
- package/dist/primitives/Icons/Icon.spec.js +175 -175
- package/dist/primitives/Icons/Icon.stories.svelte +100 -100
- package/dist/primitives/Icons/Icon.svelte +63 -63
- package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
- package/dist/primitives/Icons/ImageOutline.svelte +19 -19
- package/dist/primitives/Icons/Info.svelte +19 -19
- package/dist/primitives/Icons/InstagramIcon.svelte +19 -19
- package/dist/primitives/Icons/LogoInstagram.svelte +15 -15
- package/dist/primitives/Icons/Message.svelte +27 -27
- package/dist/primitives/Icons/MoonIcon.svelte +16 -16
- package/dist/primitives/Icons/More.svelte +33 -33
- package/dist/primitives/Icons/MoreHori.spec.js +67 -67
- package/dist/primitives/Icons/MoreHori.svelte +34 -34
- package/dist/primitives/Icons/Notification.svelte +26 -26
- package/dist/primitives/Icons/Payment.svelte +26 -26
- package/dist/primitives/Icons/Profile.svelte +33 -33
- package/dist/primitives/Icons/Reload.svelte +41 -41
- package/dist/primitives/Icons/Shows.svelte +33 -33
- package/dist/primitives/Icons/Signout.svelte +33 -33
- package/dist/primitives/Icons/SunIcon.svelte +19 -19
- package/dist/primitives/Icons/TiktokIcon.svelte +13 -13
- package/dist/primitives/Icons/TrashBinOutline.svelte +19 -19
- package/dist/primitives/Icons/TwitterIcon.svelte +13 -13
- package/dist/primitives/Icons/WarningIcon.spec.js +30 -30
- package/dist/primitives/Icons/WarningIcon.svelte +24 -24
- package/dist/primitives/Input/Input.spec.js +573 -573
- package/dist/primitives/Input/Input.stories.svelte +139 -139
- package/dist/primitives/Input/Input.svelte +444 -444
- package/dist/primitives/Input/Select.spec.js +218 -218
- package/dist/primitives/Input/Select.stories.svelte +112 -112
- package/dist/primitives/Input/Select.svelte +232 -232
- package/dist/primitives/Input/Textarea.stories.svelte +137 -137
- package/dist/primitives/Input/Textarea.svelte +79 -79
- package/dist/primitives/Label/Label.svelte +37 -37
- package/dist/primitives/Modal/Modal.spec.js +95 -95
- package/dist/primitives/Modal/Modal.stories.svelte +86 -86
- package/dist/primitives/Modal/Modal.svelte +158 -158
- package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
- package/dist/primitives/Pagination/Pagination.svelte +261 -261
- package/dist/primitives/Radio/Radio.stories.svelte +80 -80
- package/dist/primitives/Radio/Radio.svelte +67 -67
- package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
- package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
- package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
- package/dist/primitives/Skeleton/Skeleton.svelte +52 -52
- package/dist/primitives/Spinner/Spinner.spec.js +75 -75
- package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
- package/dist/primitives/Spinner/Spinner.svelte +57 -57
- package/dist/primitives/Tabs/TabItem.svelte +51 -51
- package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
- package/dist/primitives/Tabs/Tabs.svelte +128 -128
- package/dist/primitives/Toggle.spec.js +127 -127
- package/dist/primitives/Toggle.stories.svelte +92 -92
- package/dist/primitives/Toggle.svelte +71 -71
- package/dist/primitives/Typography/Typography.svelte +53 -53
- package/dist/primitives/ValidationError.spec.js +103 -103
- package/dist/primitives/ValidationError.stories.svelte +111 -111
- package/dist/primitives/ValidationError.svelte +29 -29
- package/dist/recipes/CropImage/CropImage.spec.js +216 -216
- package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
- package/dist/recipes/CropImage/CropImage.svelte +238 -238
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
- package/dist/recipes/ImageUploader/ImageUploader.svelte +980 -980
- package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +47 -47
- package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
- package/dist/recipes/feedback/ErrorDisplay.stories.svelte +112 -112
- package/dist/recipes/feedback/ErrorDisplay.svelte +38 -38
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +129 -129
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +167 -167
- package/dist/recipes/fields/CheckboxField.svelte +85 -85
- package/dist/recipes/fields/FormField.svelte +58 -58
- package/dist/recipes/fields/RadioGroup.svelte +95 -95
- package/dist/recipes/fields/SelectField.svelte +82 -82
- package/dist/recipes/fields/TextareaField.svelte +101 -101
- package/dist/recipes/fields/ToggleField.svelte +60 -60
- package/dist/recipes/fields/index.js +7 -7
- package/dist/recipes/inputs/MultiSelect.spec.js +257 -257
- package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
- package/dist/recipes/inputs/MultiSelect.svelte +244 -244
- package/dist/recipes/inputs/OTPInput.spec.js +238 -238
- package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
- package/dist/recipes/inputs/OTPInput.svelte +102 -102
- package/dist/recipes/inputs/PasswordInput.svelte +100 -100
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.spec.js +173 -173
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +108 -108
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.spec.js +300 -300
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +165 -165
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +337 -337
- package/dist/recipes/inputs/Search.svelte +85 -85
- package/dist/recipes/inputs/SelectDropdown.svelte +161 -161
- package/dist/recipes/modals/AlertModal.svelte +130 -130
- package/dist/recipes/modals/ConfirmationModal.spec.js +191 -191
- package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
- package/dist/recipes/modals/ConfirmationModal.svelte +152 -152
- package/dist/recipes/modals/InputModal.svelte +182 -182
- package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
- package/dist/recipes/modals/ModalStateManager.svelte +77 -77
- package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
- package/dist/recipes/modals/StatusModal.svelte +206 -206
- package/dist/services/EventService.js +75 -75
- package/dist/services/EventService.spec.js +217 -217
- package/dist/services/ShowService.spec.js +342 -342
- package/dist/stores/auth.js +93 -6
- package/dist/stores/auth.spec.js +310 -2
- package/dist/stores/toaster.js +13 -13
- package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
- package/dist/stories/ButtonAuditReview.svelte +427 -427
- package/dist/stories/PatternsGallery.stories.svelte +19 -19
- package/dist/stories/PatternsGallery.svelte +388 -388
- package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
- package/dist/stories/PrimitivesGallery.svelte +752 -752
- package/dist/stories/RecipesGallery.stories.svelte +19 -19
- package/dist/stories/RecipesGallery.svelte +441 -441
- package/dist/stories/button-audit-manifest.json +11186 -11186
- package/dist/tailwind/preset.cjs +82 -82
- package/dist/telemetry.js +357 -357
- package/dist/tokens/tokens.css +87 -87
- package/dist/utils/apiConfig.js +49 -49
- package/dist/utils/utils.js +9 -1
- package/package.json +233 -191
package/dist/stores/auth.js
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import { writable } from "svelte/store";
|
|
1
|
+
import { writable, get, derived } from "svelte/store";
|
|
2
|
+
import { jwtDecode } from "jwt-decode";
|
|
2
3
|
|
|
3
4
|
// Store to manage authentication state
|
|
4
5
|
export const auth = writable({
|
|
5
6
|
isAuthenticated: false,
|
|
6
7
|
token: null,
|
|
8
|
+
refreshToken: null,
|
|
7
9
|
userDetails: null, // To store email and first name
|
|
10
|
+
tokenExpiry: null, // Token expiration timestamp
|
|
11
|
+
permissions: null, // RBAC permissions
|
|
12
|
+
context: null, // User context (performer)
|
|
8
13
|
});
|
|
9
14
|
|
|
15
|
+
// Derived store for checking if user has performer permissions
|
|
16
|
+
export const isPerformer = derived(auth, ($auth) =>
|
|
17
|
+
$auth.context?.contextType === 'performer' || $auth.isAuthenticated
|
|
18
|
+
);
|
|
19
|
+
|
|
10
20
|
// Function to set authentication state
|
|
11
21
|
export const setAuthState = (state) => {
|
|
12
22
|
auth.set(state);
|
|
@@ -14,23 +24,100 @@ export const setAuthState = (state) => {
|
|
|
14
24
|
|
|
15
25
|
// Function to clear the authentication state
|
|
16
26
|
export const clearAuthState = () => {
|
|
17
|
-
auth.set({
|
|
27
|
+
auth.set({
|
|
28
|
+
isAuthenticated: false,
|
|
29
|
+
token: null,
|
|
30
|
+
refreshToken: null,
|
|
31
|
+
userDetails: null,
|
|
32
|
+
tokenExpiry: null,
|
|
33
|
+
permissions: null,
|
|
34
|
+
context: null,
|
|
35
|
+
});
|
|
18
36
|
};
|
|
19
37
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
38
|
+
// Parse cookies helper
|
|
39
|
+
const parseCookies = () => {
|
|
40
|
+
if (typeof document === "undefined") return {};
|
|
41
|
+
return Object.fromEntries(
|
|
23
42
|
document.cookie
|
|
24
43
|
.split("; ")
|
|
44
|
+
.filter(c => c)
|
|
25
45
|
.map((c) => c.split("="))
|
|
26
|
-
.map(([k, v]) => [k, decodeURIComponent(v)])
|
|
46
|
+
.map(([k, v]) => [k, decodeURIComponent(v || "")])
|
|
27
47
|
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Get token expiry from JWT
|
|
51
|
+
const getTokenExpiry = (token) => {
|
|
52
|
+
if (!token) return null;
|
|
53
|
+
try {
|
|
54
|
+
const decoded = jwtDecode(token);
|
|
55
|
+
return decoded.exp ? decoded.exp * 1000 : null; // Convert to milliseconds
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Check if token is expired or about to expire (within 5 minutes)
|
|
62
|
+
export const isTokenExpiringSoon = (bufferMs = 5 * 60 * 1000) => {
|
|
63
|
+
const state = get(auth);
|
|
64
|
+
if (!state.tokenExpiry) return true;
|
|
65
|
+
return Date.now() >= (state.tokenExpiry - bufferMs);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Initialize the store from cookies
|
|
69
|
+
export const initializeAuthState = () => {
|
|
70
|
+
const cookies = parseCookies();
|
|
28
71
|
|
|
29
72
|
if (cookies.performer_token) {
|
|
73
|
+
const tokenExpiry = getTokenExpiry(cookies.performer_token);
|
|
74
|
+
|
|
30
75
|
setAuthState({
|
|
31
76
|
isAuthenticated: true,
|
|
32
77
|
token: cookies.performer_token,
|
|
78
|
+
refreshToken: cookies.performer_refresh_token || null,
|
|
33
79
|
userDetails: cookies.userDetails ? JSON.parse(cookies.userDetails) : null,
|
|
80
|
+
tokenExpiry,
|
|
34
81
|
});
|
|
35
82
|
}
|
|
36
83
|
};
|
|
84
|
+
|
|
85
|
+
// Update tokens after a refresh
|
|
86
|
+
export const updateTokens = (accessToken, refreshToken) => {
|
|
87
|
+
auth.update(state => ({
|
|
88
|
+
...state,
|
|
89
|
+
token: accessToken,
|
|
90
|
+
refreshToken: refreshToken || state.refreshToken,
|
|
91
|
+
tokenExpiry: getTokenExpiry(accessToken),
|
|
92
|
+
}));
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Update permissions
|
|
96
|
+
export const setPermissions = (permissions) => {
|
|
97
|
+
auth.update(state => ({
|
|
98
|
+
...state,
|
|
99
|
+
permissions,
|
|
100
|
+
}));
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Set user context
|
|
104
|
+
export const setContext = (context) => {
|
|
105
|
+
auth.update(state => ({
|
|
106
|
+
...state,
|
|
107
|
+
context,
|
|
108
|
+
}));
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Check if user has a specific permission
|
|
112
|
+
export const hasPermission = (category, permission) => {
|
|
113
|
+
const state = get(auth);
|
|
114
|
+
if (!state.permissions) return false;
|
|
115
|
+
|
|
116
|
+
// Performers have limited permissions by design
|
|
117
|
+
return state.permissions[category]?.[permission] ?? false;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Get current permissions
|
|
121
|
+
export const getPermissions = () => {
|
|
122
|
+
return get(auth).permissions;
|
|
123
|
+
};
|
package/dist/stores/auth.spec.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
import { get } from 'svelte/store';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
auth,
|
|
5
|
+
isPerformer,
|
|
6
|
+
setAuthState,
|
|
7
|
+
clearAuthState,
|
|
8
|
+
initializeAuthState,
|
|
9
|
+
updateTokens,
|
|
10
|
+
setPermissions,
|
|
11
|
+
setContext,
|
|
12
|
+
hasPermission,
|
|
13
|
+
getPermissions,
|
|
14
|
+
isTokenExpiringSoon
|
|
15
|
+
} from './auth';
|
|
16
|
+
|
|
17
|
+
// Mock jwt-decode
|
|
18
|
+
vi.mock('jwt-decode', () => ({
|
|
19
|
+
jwtDecode: vi.fn((token) => {
|
|
20
|
+
// Parse mock tokens in format: "token-exp-{timestamp}"
|
|
21
|
+
if (token.startsWith('token-exp-')) {
|
|
22
|
+
const exp = parseInt(token.replace('token-exp-', ''), 10);
|
|
23
|
+
return { exp: exp / 1000 }; // Convert ms to seconds (JWT uses seconds)
|
|
24
|
+
}
|
|
25
|
+
// Default: return token that expires in 1 hour
|
|
26
|
+
return { exp: (Date.now() + 3600000) / 1000 };
|
|
27
|
+
})
|
|
28
|
+
}));
|
|
4
29
|
|
|
5
30
|
describe('auth store', () => {
|
|
6
31
|
beforeEach(() => {
|
|
@@ -136,4 +161,287 @@ describe('auth store', () => {
|
|
|
136
161
|
expect(values).toEqual([false, true, false]);
|
|
137
162
|
});
|
|
138
163
|
});
|
|
164
|
+
|
|
165
|
+
describe('updateTokens', () => {
|
|
166
|
+
it('updates access token and computes new expiry', () => {
|
|
167
|
+
setAuthState({
|
|
168
|
+
isAuthenticated: true,
|
|
169
|
+
token: 'old-token',
|
|
170
|
+
refreshToken: 'old-refresh',
|
|
171
|
+
userDetails: null,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
updateTokens('new-access-token', 'new-refresh-token');
|
|
175
|
+
|
|
176
|
+
const state = get(auth);
|
|
177
|
+
expect(state.token).toBe('new-access-token');
|
|
178
|
+
expect(state.refreshToken).toBe('new-refresh-token');
|
|
179
|
+
expect(state.tokenExpiry).toBeDefined();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('preserves existing refresh token if not provided', () => {
|
|
183
|
+
setAuthState({
|
|
184
|
+
isAuthenticated: true,
|
|
185
|
+
token: 'old-token',
|
|
186
|
+
refreshToken: 'existing-refresh',
|
|
187
|
+
userDetails: null,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
updateTokens('new-access-token');
|
|
191
|
+
|
|
192
|
+
const state = get(auth);
|
|
193
|
+
expect(state.token).toBe('new-access-token');
|
|
194
|
+
expect(state.refreshToken).toBe('existing-refresh');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('preserves other state properties when updating tokens', () => {
|
|
198
|
+
setAuthState({
|
|
199
|
+
isAuthenticated: true,
|
|
200
|
+
token: 'old-token',
|
|
201
|
+
refreshToken: 'refresh',
|
|
202
|
+
userDetails: { email: 'test@test.com' },
|
|
203
|
+
permissions: { events: { read: true } },
|
|
204
|
+
context: { contextType: 'performer' },
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
updateTokens('new-token');
|
|
208
|
+
|
|
209
|
+
const state = get(auth);
|
|
210
|
+
expect(state.userDetails).toEqual({ email: 'test@test.com' });
|
|
211
|
+
expect(state.permissions).toEqual({ events: { read: true } });
|
|
212
|
+
expect(state.context).toEqual({ contextType: 'performer' });
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe('isTokenExpiringSoon', () => {
|
|
217
|
+
it('returns true when no token expiry is set', () => {
|
|
218
|
+
clearAuthState();
|
|
219
|
+
expect(isTokenExpiringSoon()).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('returns true when token is expired', () => {
|
|
223
|
+
const pastTime = Date.now() - 10000; // 10 seconds ago
|
|
224
|
+
setAuthState({
|
|
225
|
+
isAuthenticated: true,
|
|
226
|
+
token: 'token',
|
|
227
|
+
tokenExpiry: pastTime,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(isTokenExpiringSoon()).toBe(true);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('returns true when token expires within buffer time', () => {
|
|
234
|
+
const soonExpiry = Date.now() + (2 * 60 * 1000); // 2 minutes from now
|
|
235
|
+
setAuthState({
|
|
236
|
+
isAuthenticated: true,
|
|
237
|
+
token: 'token',
|
|
238
|
+
tokenExpiry: soonExpiry,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Default buffer is 5 minutes, so 2 minutes is within buffer
|
|
242
|
+
expect(isTokenExpiringSoon()).toBe(true);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('returns false when token has plenty of time left', () => {
|
|
246
|
+
const futureExpiry = Date.now() + (30 * 60 * 1000); // 30 minutes from now
|
|
247
|
+
setAuthState({
|
|
248
|
+
isAuthenticated: true,
|
|
249
|
+
token: 'token',
|
|
250
|
+
tokenExpiry: futureExpiry,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
expect(isTokenExpiringSoon()).toBe(false);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('accepts custom buffer time', () => {
|
|
257
|
+
const expiry = Date.now() + (10 * 60 * 1000); // 10 minutes from now
|
|
258
|
+
setAuthState({
|
|
259
|
+
isAuthenticated: true,
|
|
260
|
+
token: 'token',
|
|
261
|
+
tokenExpiry: expiry,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// With 5 minute buffer (default), should be fine
|
|
265
|
+
expect(isTokenExpiringSoon(5 * 60 * 1000)).toBe(false);
|
|
266
|
+
|
|
267
|
+
// With 15 minute buffer, should be expiring soon
|
|
268
|
+
expect(isTokenExpiringSoon(15 * 60 * 1000)).toBe(true);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe('setPermissions and getPermissions', () => {
|
|
273
|
+
it('sets permissions on auth state', () => {
|
|
274
|
+
const permissions = {
|
|
275
|
+
events: { read: true, write: false },
|
|
276
|
+
shows: { read: true, write: true },
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
setPermissions(permissions);
|
|
280
|
+
|
|
281
|
+
const state = get(auth);
|
|
282
|
+
expect(state.permissions).toEqual(permissions);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('getPermissions returns current permissions', () => {
|
|
286
|
+
const permissions = {
|
|
287
|
+
events: { read: true },
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
setPermissions(permissions);
|
|
291
|
+
|
|
292
|
+
expect(getPermissions()).toEqual(permissions);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('getPermissions returns null when no permissions set', () => {
|
|
296
|
+
clearAuthState();
|
|
297
|
+
expect(getPermissions()).toBe(null);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('preserves other state when setting permissions', () => {
|
|
301
|
+
setAuthState({
|
|
302
|
+
isAuthenticated: true,
|
|
303
|
+
token: 'test-token',
|
|
304
|
+
userDetails: { email: 'test@test.com' },
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
setPermissions({ events: { read: true } });
|
|
308
|
+
|
|
309
|
+
const state = get(auth);
|
|
310
|
+
expect(state.isAuthenticated).toBe(true);
|
|
311
|
+
expect(state.token).toBe('test-token');
|
|
312
|
+
expect(state.userDetails).toEqual({ email: 'test@test.com' });
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('setContext', () => {
|
|
317
|
+
it('sets user context on auth state', () => {
|
|
318
|
+
const context = {
|
|
319
|
+
contextType: 'performer',
|
|
320
|
+
performerId: 'perf-123',
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
setContext(context);
|
|
324
|
+
|
|
325
|
+
const state = get(auth);
|
|
326
|
+
expect(state.context).toEqual(context);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('preserves other state when setting context', () => {
|
|
330
|
+
setAuthState({
|
|
331
|
+
isAuthenticated: true,
|
|
332
|
+
token: 'test-token',
|
|
333
|
+
permissions: { events: { read: true } },
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
setContext({ contextType: 'performer' });
|
|
337
|
+
|
|
338
|
+
const state = get(auth);
|
|
339
|
+
expect(state.isAuthenticated).toBe(true);
|
|
340
|
+
expect(state.token).toBe('test-token');
|
|
341
|
+
expect(state.permissions).toEqual({ events: { read: true } });
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('can update existing context', () => {
|
|
345
|
+
setContext({ contextType: 'performer', performerId: 'old' });
|
|
346
|
+
setContext({ contextType: 'performer', performerId: 'new' });
|
|
347
|
+
|
|
348
|
+
const state = get(auth);
|
|
349
|
+
expect(state.context.performerId).toBe('new');
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
describe('hasPermission', () => {
|
|
354
|
+
it('returns false when no permissions are set', () => {
|
|
355
|
+
clearAuthState();
|
|
356
|
+
expect(hasPermission('events', 'read')).toBe(false);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('returns true when permission exists and is true', () => {
|
|
360
|
+
setPermissions({
|
|
361
|
+
events: { read: true, write: false },
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
expect(hasPermission('events', 'read')).toBe(true);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('returns false when permission exists and is false', () => {
|
|
368
|
+
setPermissions({
|
|
369
|
+
events: { read: true, write: false },
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
expect(hasPermission('events', 'write')).toBe(false);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('returns false when category does not exist', () => {
|
|
376
|
+
setPermissions({
|
|
377
|
+
events: { read: true },
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
expect(hasPermission('shows', 'read')).toBe(false);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('returns false when permission does not exist in category', () => {
|
|
384
|
+
setPermissions({
|
|
385
|
+
events: { read: true },
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
expect(hasPermission('events', 'delete')).toBe(false);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('works with nested permission categories', () => {
|
|
392
|
+
setPermissions({
|
|
393
|
+
events: { read: true, write: true },
|
|
394
|
+
shows: { read: true, write: false, delete: false },
|
|
395
|
+
admin: { read: false },
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(hasPermission('events', 'read')).toBe(true);
|
|
399
|
+
expect(hasPermission('events', 'write')).toBe(true);
|
|
400
|
+
expect(hasPermission('shows', 'read')).toBe(true);
|
|
401
|
+
expect(hasPermission('shows', 'write')).toBe(false);
|
|
402
|
+
expect(hasPermission('admin', 'read')).toBe(false);
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
describe('isPerformer derived store', () => {
|
|
407
|
+
it('returns true when context type is performer', () => {
|
|
408
|
+
setContext({ contextType: 'performer' });
|
|
409
|
+
|
|
410
|
+
expect(get(isPerformer)).toBe(true);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('returns true when user is authenticated (fallback)', () => {
|
|
414
|
+
setAuthState({
|
|
415
|
+
isAuthenticated: true,
|
|
416
|
+
token: 'token',
|
|
417
|
+
userDetails: null,
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
expect(get(isPerformer)).toBe(true);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('returns false when not authenticated and no performer context', () => {
|
|
424
|
+
clearAuthState();
|
|
425
|
+
|
|
426
|
+
expect(get(isPerformer)).toBe(false);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('updates reactively when context changes', () => {
|
|
430
|
+
const values = [];
|
|
431
|
+
const unsubscribe = isPerformer.subscribe((value) => {
|
|
432
|
+
values.push(value);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
clearAuthState();
|
|
436
|
+
setContext({ contextType: 'performer' });
|
|
437
|
+
setContext({ contextType: 'staff' });
|
|
438
|
+
setAuthState({ isAuthenticated: true, token: 'token' });
|
|
439
|
+
|
|
440
|
+
unsubscribe();
|
|
441
|
+
|
|
442
|
+
// false (initial), true (performer context), false (staff context, not authenticated), true (authenticated)
|
|
443
|
+
expect(values).toContain(false);
|
|
444
|
+
expect(values).toContain(true);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
139
447
|
});
|
package/dist/stores/toaster.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { toast } from "svelte-sonner";
|
|
2
|
-
|
|
3
|
-
export { toast };
|
|
4
|
-
|
|
5
|
-
export const showToast = (message, type = "success") => {
|
|
6
|
-
if (type === "success") {
|
|
7
|
-
toast.success(message);
|
|
8
|
-
} else if (type === "error") {
|
|
9
|
-
toast.error(message);
|
|
10
|
-
} else {
|
|
11
|
-
toast.message(message);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
1
|
+
import { toast } from "svelte-sonner";
|
|
2
|
+
|
|
3
|
+
export { toast };
|
|
4
|
+
|
|
5
|
+
export const showToast = (message, type = "success") => {
|
|
6
|
+
if (type === "success") {
|
|
7
|
+
toast.success(message);
|
|
8
|
+
} else if (type === "error") {
|
|
9
|
+
toast.error(message);
|
|
10
|
+
} else {
|
|
11
|
+
toast.message(message);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<script module>
|
|
2
|
-
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
-
import ButtonAuditReview from "./ButtonAuditReview.svelte";
|
|
4
|
-
|
|
5
|
-
const { Story } = defineMeta({
|
|
6
|
-
title: "Design System/Button Audit Review",
|
|
7
|
-
component: ButtonAuditReview,
|
|
8
|
-
parameters: {
|
|
9
|
-
layout: 'fullscreen',
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<Story name="All Issues" />
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import ButtonAuditReview from "./ButtonAuditReview.svelte";
|
|
4
|
+
|
|
5
|
+
const { Story } = defineMeta({
|
|
6
|
+
title: "Design System/Button Audit Review",
|
|
7
|
+
component: ButtonAuditReview,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'fullscreen',
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Story name="All Issues" />
|