@licklist/design 0.78.5-dev.69 → 0.78.5-dev.70

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.
Files changed (123) hide show
  1. package/dist/styles/themes/bookedit/_fonts.scss +2 -0
  2. package/dist/v2/components/ActionMenu/ActionMenu.d.ts.map +1 -1
  3. package/dist/v2/components/ActionMenu/ActionMenu.js +5 -3
  4. package/dist/v2/components/AvatarUpload/AvatarUpload.d.ts +12 -0
  5. package/dist/v2/components/AvatarUpload/AvatarUpload.d.ts.map +1 -0
  6. package/dist/v2/components/AvatarUpload/index.d.ts +2 -0
  7. package/dist/v2/components/AvatarUpload/index.d.ts.map +1 -0
  8. package/dist/v2/components/Button/Button.d.ts +1 -1
  9. package/dist/v2/components/Button/Button.d.ts.map +1 -1
  10. package/dist/v2/components/Button/Button.scss.js +1 -1
  11. package/dist/v2/components/DataTable/DataTable.d.ts +41 -0
  12. package/dist/v2/components/DataTable/DataTable.d.ts.map +1 -0
  13. package/dist/v2/components/DataTable/index.d.ts +3 -0
  14. package/dist/v2/components/DataTable/index.d.ts.map +1 -0
  15. package/dist/v2/components/EmptyState/EmptyState.d.ts +14 -0
  16. package/dist/v2/components/EmptyState/EmptyState.d.ts.map +1 -0
  17. package/dist/v2/components/EmptyState/index.d.ts +3 -0
  18. package/dist/v2/components/EmptyState/index.d.ts.map +1 -0
  19. package/dist/v2/components/FormField/FormField.scss.js +1 -1
  20. package/dist/v2/components/InfoGrid/InfoGrid.d.ts +13 -0
  21. package/dist/v2/components/InfoGrid/InfoGrid.d.ts.map +1 -0
  22. package/dist/v2/components/InfoGrid/index.d.ts +2 -0
  23. package/dist/v2/components/InfoGrid/index.d.ts.map +1 -0
  24. package/dist/v2/components/NewTable/NewTable.scss.js +1 -1
  25. package/dist/v2/components/RadioCard/RadioCard.d.ts +17 -0
  26. package/dist/v2/components/RadioCard/RadioCard.d.ts.map +1 -0
  27. package/dist/v2/components/RadioCard/index.d.ts +2 -0
  28. package/dist/v2/components/RadioCard/index.d.ts.map +1 -0
  29. package/dist/v2/components/StatusBadge/StatusBadge.d.ts +8 -0
  30. package/dist/v2/components/StatusBadge/StatusBadge.d.ts.map +1 -0
  31. package/dist/v2/components/StatusBadge/index.d.ts +3 -0
  32. package/dist/v2/components/StatusBadge/index.d.ts.map +1 -0
  33. package/dist/v2/components/StepIndicator/StepIndicator.d.ts +9 -0
  34. package/dist/v2/components/StepIndicator/StepIndicator.d.ts.map +1 -0
  35. package/dist/v2/components/StepIndicator/index.d.ts +2 -0
  36. package/dist/v2/components/StepIndicator/index.d.ts.map +1 -0
  37. package/dist/v2/components/TableControls/TableControls.d.ts +28 -0
  38. package/dist/v2/components/TableControls/TableControls.d.ts.map +1 -0
  39. package/dist/v2/components/TableControls/index.d.ts +3 -0
  40. package/dist/v2/components/TableControls/index.d.ts.map +1 -0
  41. package/dist/v2/components/Tabs/Tabs.d.ts +15 -0
  42. package/dist/v2/components/Tabs/Tabs.d.ts.map +1 -0
  43. package/dist/v2/components/Tabs/index.d.ts +3 -0
  44. package/dist/v2/components/Tabs/index.d.ts.map +1 -0
  45. package/dist/v2/icons/index.d.ts +42 -0
  46. package/dist/v2/icons/index.d.ts.map +1 -1
  47. package/dist/v2/index.d.ts +18 -0
  48. package/dist/v2/index.d.ts.map +1 -1
  49. package/dist/v2/pages/CreateUser/CreateUserPage.d.ts +110 -0
  50. package/dist/v2/pages/CreateUser/CreateUserPage.d.ts.map +1 -0
  51. package/dist/v2/pages/CreateUser/index.d.ts +3 -0
  52. package/dist/v2/pages/CreateUser/index.d.ts.map +1 -0
  53. package/dist/v2/pages/RoleSelection/RoleSelectionPage.d.ts +26 -0
  54. package/dist/v2/pages/RoleSelection/RoleSelectionPage.d.ts.map +1 -0
  55. package/dist/v2/pages/RoleSelection/index.d.ts +3 -0
  56. package/dist/v2/pages/RoleSelection/index.d.ts.map +1 -0
  57. package/dist/v2/pages/UserDetails/UserDetailsPage.d.ts +37 -0
  58. package/dist/v2/pages/UserDetails/UserDetailsPage.d.ts.map +1 -0
  59. package/dist/v2/pages/UserDetails/index.d.ts +3 -0
  60. package/dist/v2/pages/UserDetails/index.d.ts.map +1 -0
  61. package/dist/v2/pages/auth/CreatePassword/CreatePasswordPage.d.ts.map +1 -1
  62. package/dist/v2/pages/auth/Login/LoginPage.d.ts.map +1 -1
  63. package/dist/v2/pages/auth/ResetPassword/ResetPasswordPage.d.ts.map +1 -1
  64. package/dist/v2/styles/components/Button.scss +27 -0
  65. package/package.json +2 -2
  66. package/src/styles/themes/bookedit/_fonts.scss +2 -0
  67. package/src/v2/components/ActionMenu/ActionMenu.tsx +4 -2
  68. package/src/v2/components/AvatarUpload/AvatarUpload.scss +68 -0
  69. package/src/v2/components/AvatarUpload/AvatarUpload.stories.tsx +83 -0
  70. package/src/v2/components/AvatarUpload/AvatarUpload.tsx +69 -0
  71. package/src/v2/components/AvatarUpload/index.ts +1 -0
  72. package/src/v2/components/Button/Button.tsx +1 -0
  73. package/src/v2/components/DataTable/DataTable.scss +181 -0
  74. package/src/v2/components/DataTable/DataTable.tsx +256 -0
  75. package/src/v2/components/DataTable/index.ts +7 -0
  76. package/src/v2/components/EmptyState/EmptyState.scss +39 -0
  77. package/src/v2/components/EmptyState/EmptyState.stories.tsx +45 -0
  78. package/src/v2/components/EmptyState/EmptyState.tsx +37 -0
  79. package/src/v2/components/EmptyState/index.ts +2 -0
  80. package/src/v2/components/FormField/FormField.scss +12 -0
  81. package/src/v2/components/InfoGrid/InfoGrid.scss +51 -0
  82. package/src/v2/components/InfoGrid/InfoGrid.stories.tsx +76 -0
  83. package/src/v2/components/InfoGrid/InfoGrid.tsx +28 -0
  84. package/src/v2/components/InfoGrid/index.ts +1 -0
  85. package/src/v2/components/NewTable/NewTable.scss +4 -4
  86. package/src/v2/components/RadioCard/RadioCard.scss +76 -0
  87. package/src/v2/components/RadioCard/RadioCard.stories.tsx +115 -0
  88. package/src/v2/components/RadioCard/RadioCard.tsx +68 -0
  89. package/src/v2/components/RadioCard/index.ts +1 -0
  90. package/src/v2/components/StatusBadge/StatusBadge.scss +53 -0
  91. package/src/v2/components/StatusBadge/StatusBadge.tsx +31 -0
  92. package/src/v2/components/StatusBadge/index.ts +2 -0
  93. package/src/v2/components/StepIndicator/StepIndicator.scss +62 -0
  94. package/src/v2/components/StepIndicator/StepIndicator.stories.tsx +37 -0
  95. package/src/v2/components/StepIndicator/StepIndicator.tsx +41 -0
  96. package/src/v2/components/StepIndicator/index.ts +1 -0
  97. package/src/v2/components/TableControls/TableControls.scss +63 -0
  98. package/src/v2/components/TableControls/TableControls.tsx +110 -0
  99. package/src/v2/components/TableControls/index.ts +7 -0
  100. package/src/v2/components/Tabs/Tabs.scss +36 -0
  101. package/src/v2/components/Tabs/Tabs.stories.tsx +75 -0
  102. package/src/v2/components/Tabs/Tabs.tsx +52 -0
  103. package/src/v2/components/Tabs/index.ts +2 -0
  104. package/src/v2/icons/index.tsx +219 -0
  105. package/src/v2/index.ts +98 -0
  106. package/src/v2/pages/CreateUser/CreateUserPage.scss +760 -0
  107. package/src/v2/pages/CreateUser/CreateUserPage.stories.tsx +157 -0
  108. package/src/v2/pages/CreateUser/CreateUserPage.tsx +1062 -0
  109. package/src/v2/pages/CreateUser/index.ts +13 -0
  110. package/src/v2/pages/RoleSelection/RoleSelectionPage.scss +193 -0
  111. package/src/v2/pages/RoleSelection/RoleSelectionPage.stories.tsx +112 -0
  112. package/src/v2/pages/RoleSelection/RoleSelectionPage.tsx +127 -0
  113. package/src/v2/pages/RoleSelection/index.ts +2 -0
  114. package/src/v2/pages/UserDetails/UserDetailsPage.scss +236 -0
  115. package/src/v2/pages/UserDetails/UserDetailsPage.stories.tsx +84 -0
  116. package/src/v2/pages/UserDetails/UserDetailsPage.tsx +210 -0
  117. package/src/v2/pages/UserDetails/index.ts +2 -0
  118. package/src/v2/pages/auth/AuthLayout/AuthLayout.scss +8 -6
  119. package/src/v2/pages/auth/CreatePassword/CreatePasswordPage.tsx +1 -3
  120. package/src/v2/pages/auth/Login/LoginPage.tsx +1 -3
  121. package/src/v2/pages/auth/ResetPassword/ResetPasswordPage.scss +2 -0
  122. package/src/v2/pages/auth/ResetPassword/ResetPasswordPage.tsx +1 -2
  123. package/src/v2/styles/components/Button.scss +27 -0
@@ -0,0 +1,13 @@
1
+ export { CreateUserPage } from './CreateUserPage'
2
+ export type {
3
+ CreateUserPageProps,
4
+ ExistingUser,
5
+ UserAssignment,
6
+ EntityResult,
7
+ VenueAssignment,
8
+ ProviderAssignment,
9
+ NestedProvider,
10
+ InviteData,
11
+ GlobalRole,
12
+ ProviderRole,
13
+ } from './CreateUserPage'
@@ -0,0 +1,193 @@
1
+ @import '../../styles/index.scss';
2
+
3
+ .role-selection-page {
4
+ display: flex;
5
+ flex-direction: column;
6
+ min-height: 100vh;
7
+ background: var(--surface-primary, #ffffff);
8
+
9
+ // ── Header ────────────────────────────────────────────────────────────────
10
+ &__header {
11
+ display: flex;
12
+ align-items: center;
13
+ justify-content: space-between;
14
+ padding: 16px 24px;
15
+ border-bottom: 1px solid var(--border-primary, #e8e9ef);
16
+ background: var(--surface-primary, #ffffff);
17
+ position: sticky;
18
+ top: 0;
19
+ z-index: 10;
20
+ }
21
+
22
+ &__title {
23
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
24
+ font-size: 18px;
25
+ font-weight: 700;
26
+ line-height: 24px;
27
+ color: var(--label-primary, #121e52);
28
+ margin: 0;
29
+ }
30
+
31
+ // ── Body ──────────────────────────────────────────────────────────────────
32
+ &__body {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 16px;
36
+ padding: 24px;
37
+ width: 100%;
38
+ max-width: 700px;
39
+ margin: 0 auto;
40
+ }
41
+
42
+ // ── Back button ───────────────────────────────────────────────────────────
43
+ &__back {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ gap: 6px;
47
+ background: none;
48
+ border: none;
49
+ cursor: pointer;
50
+ padding: 6px 8px;
51
+ border-radius: var(--radius-sm, 4px);
52
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
53
+ font-size: 14px;
54
+ font-weight: 500;
55
+ color: var(--label-action, #6200ee);
56
+ transition: background 0.15s ease;
57
+
58
+ &:hover {
59
+ background: var(--surface-action-soft, #f3e8ff);
60
+ }
61
+
62
+ svg path {
63
+ stroke: currentColor;
64
+ }
65
+ }
66
+
67
+ // ── Error banner ──────────────────────────────────────────────────────────
68
+ &__error-banner {
69
+ width: 100%;
70
+ padding: 12px 16px;
71
+ background: var(--surface-status-error-soft, #fef2f2);
72
+ border: 1px solid var(--border-status-error, #fecaca);
73
+ border-radius: var(--radius-md, 8px);
74
+ font-size: 14px;
75
+ color: var(--label-status-error, #ef4444);
76
+ }
77
+
78
+ // ── Step header ───────────────────────────────────────────────────────────
79
+ &__step-header {
80
+ display: flex;
81
+ flex-direction: column;
82
+ gap: 6px;
83
+ }
84
+
85
+ &__step-title {
86
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
87
+ font-size: 20px;
88
+ font-weight: 600;
89
+ color: var(--label-primary, #121e52);
90
+ margin: 0;
91
+
92
+ strong {
93
+ font-weight: 700;
94
+ }
95
+ }
96
+
97
+ &__step-desc {
98
+ font-size: 14px;
99
+ color: var(--label-secondary, #626a90);
100
+ margin: 0;
101
+ }
102
+
103
+ // ── Role cards ────────────────────────────────────────────────────────────
104
+ &__roles {
105
+ display: flex;
106
+ flex-direction: column;
107
+ gap: 10px;
108
+ width: 100%;
109
+ }
110
+
111
+ &__role-card {
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 14px;
115
+ padding: 14px 16px;
116
+ background: var(--surface-primary, #ffffff);
117
+ border: 1.5px solid var(--border-primary, #e8e9ef);
118
+ border-radius: var(--radius-md, 8px);
119
+ cursor: pointer;
120
+ transition: border-color 0.15s ease, background 0.15s ease;
121
+
122
+ &:hover {
123
+ border-color: var(--border-selected, #6200ee);
124
+ background: var(--surface-action-soft, #f3e8ff);
125
+ }
126
+
127
+ &--selected {
128
+ border-color: var(--border-selected, #6200ee);
129
+ background: var(--surface-action-soft, #f3e8ff);
130
+ }
131
+ }
132
+
133
+ &__role-input {
134
+ // Hidden — visual state driven by the card
135
+ position: absolute;
136
+ opacity: 0;
137
+ pointer-events: none;
138
+ width: 0;
139
+ height: 0;
140
+ }
141
+
142
+ &__role-content {
143
+ display: flex;
144
+ flex-direction: column;
145
+ gap: 2px;
146
+ flex: 1;
147
+ }
148
+
149
+ &__role-label {
150
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
151
+ font-size: 15px;
152
+ font-weight: 600;
153
+ color: var(--label-primary, #121e52);
154
+
155
+ .role-selection-page__role-card--selected & {
156
+ color: var(--label-action, #6200ee);
157
+ }
158
+ }
159
+
160
+ &__role-desc {
161
+ font-size: 13px;
162
+ color: var(--label-secondary, #626a90);
163
+ }
164
+
165
+ // Custom radio indicator
166
+ &__role-radio {
167
+ flex-shrink: 0;
168
+ width: 18px;
169
+ height: 18px;
170
+ border-radius: 50%;
171
+ border: 2px solid var(--border-primary, #e8e9ef);
172
+ background: var(--surface-primary, #ffffff);
173
+ transition: border-color 0.15s ease;
174
+ position: relative;
175
+
176
+ &::after {
177
+ content: '';
178
+ position: absolute;
179
+ inset: 3px;
180
+ border-radius: 50%;
181
+ background: transparent;
182
+ transition: background 0.15s ease;
183
+ }
184
+
185
+ .role-selection-page__role-card--selected & {
186
+ border-color: var(--border-selected, #6200ee);
187
+
188
+ &::after {
189
+ background: var(--label-action, #6200ee);
190
+ }
191
+ }
192
+ }
193
+ }
@@ -0,0 +1,112 @@
1
+ import React from 'react'
2
+ import type { Meta, StoryObj } from '@storybook/react'
3
+ import { RoleSelectionPage } from './RoleSelectionPage'
4
+ import type { RoleOption } from './RoleSelectionPage'
5
+
6
+ // ─── Mock role sets ───────────────────────────────────────────────────────────
7
+
8
+ /** Admin-panel: choose the user's global role or mark them as a provider user */
9
+ const globalRoles: RoleOption[] = [
10
+ {
11
+ value: 'super_admin',
12
+ label: 'Super Admin',
13
+ description: 'Full platform access including billing and system settings',
14
+ },
15
+ {
16
+ value: 'system_admin',
17
+ label: 'System Admin',
18
+ description: 'Manage users, providers, and platform configuration',
19
+ },
20
+ {
21
+ value: 'admin',
22
+ label: 'Provider User',
23
+ description: 'Access scoped to the providers they are assigned to',
24
+ },
25
+ ]
26
+
27
+ /** Provider / company team: the six provider-level roles */
28
+ const providerRoles: RoleOption[] = [
29
+ { value: 'admin', label: 'Admin', description: 'Full access to provider settings and team management' },
30
+ { value: 'manager', label: 'Manager', description: 'Can manage bookings and view reports' },
31
+ { value: 'operations', label: 'Operations', description: 'Can edit bookings and customer information' },
32
+ { value: 'staff', label: 'Staff', description: 'Can view and process bookings' },
33
+ { value: 'viewer', label: 'Viewer', description: 'Read-only access to provider data' },
34
+ { value: 'desk', label: 'Front Desk', description: 'Front desk access for customer check-in' },
35
+ ]
36
+
37
+ function delay(ms: number) {
38
+ return new Promise<void>((r) => setTimeout(r, ms))
39
+ }
40
+
41
+ // ─── Meta ─────────────────────────────────────────────────────────────────────
42
+
43
+ const meta: Meta<typeof RoleSelectionPage> = {
44
+ title: 'v2/Pages/RoleSelection',
45
+ component: RoleSelectionPage,
46
+ parameters: { layout: 'fullscreen' },
47
+ }
48
+
49
+ export default meta
50
+ type Story = StoryObj<typeof RoleSelectionPage>
51
+
52
+ // ─── Stories ──────────────────────────────────────────────────────────────────
53
+
54
+ /**
55
+ * **Global Role** — `/admin/users/add` (step 3)
56
+ *
57
+ * A super or system admin chooses the platform-level role for the new user:
58
+ * Super Admin, System Admin, or Provider User (scoped access).
59
+ */
60
+ export const GlobalRoles: Story = {
61
+ name: 'Global Roles (Admin Panel)',
62
+ args: {
63
+ pageTitle: 'Add User',
64
+ userName: 'Jane',
65
+ roles: globalRoles,
66
+ defaultRole: 'admin',
67
+ submitLabel: 'Next',
68
+ onSubmit: (role) => console.log('Selected global role:', role),
69
+ onBack: () => console.log('Back'),
70
+ onCancel: () => console.log('Cancel'),
71
+ },
72
+ }
73
+
74
+ /**
75
+ * **Provider Role** — `/venue|promoter/{id}/settings/team-settings/add` (step 3)
76
+ *
77
+ * A provider admin assigns one of the six scoped roles to the team member.
78
+ * The submit label changes to "Send Invitation" for new users.
79
+ */
80
+ export const ProviderRoles: Story = {
81
+ name: 'Provider Roles (Provider Team)',
82
+ args: {
83
+ pageTitle: 'Add Team Member',
84
+ userName: 'Tom',
85
+ roles: providerRoles,
86
+ defaultRole: 'admin',
87
+ submitLabel: 'Send Invitation',
88
+ onSubmit: async (role) => { await delay(1000); console.log('Invited with role:', role) },
89
+ onBack: () => console.log('Back'),
90
+ onCancel: () => console.log('Cancel'),
91
+ },
92
+ }
93
+
94
+ /**
95
+ * **Provider Role — Existing User** — same flow, different CTA label.
96
+ *
97
+ * When the user already exists the button reads "Add User" instead of
98
+ * "Send Invitation" since no invite email is needed.
99
+ */
100
+ export const ProviderRolesExistingUser: Story = {
101
+ name: 'Provider Roles — Existing User',
102
+ args: {
103
+ pageTitle: 'Add Team Member',
104
+ userName: 'Jane',
105
+ roles: providerRoles,
106
+ defaultRole: 'manager',
107
+ submitLabel: 'Add User',
108
+ onSubmit: async (role) => { await delay(800); console.log('User added with role:', role) },
109
+ onBack: () => console.log('Back'),
110
+ onCancel: () => console.log('Cancel'),
111
+ },
112
+ }
@@ -0,0 +1,127 @@
1
+ import React, { useState } from 'react'
2
+ import { Button } from '../../components/Button'
3
+ import { ArrowLeftIcon } from '../../icons'
4
+ import './RoleSelectionPage.scss'
5
+
6
+ // ─── Types ────────────────────────────────────────────────────────────────────
7
+
8
+ export interface RoleOption {
9
+ value: string
10
+ label: string
11
+ description?: string
12
+ }
13
+
14
+ export interface RoleSelectionPageProps {
15
+ /** Page-level title shown in the sticky header */
16
+ pageTitle?: string
17
+ /** First name of the user being added — shown in the step heading */
18
+ userName?: string
19
+ /** The role options to display as radio cards */
20
+ roles: RoleOption[]
21
+ /** Pre-selected role value */
22
+ defaultRole?: string
23
+ /** Label for the submit / CTA button — defaults to "Send Invitation" */
24
+ submitLabel?: string
25
+ onSubmit: (role: string) => void
26
+ onBack?: () => void
27
+ onCancel?: () => void
28
+ isLoading?: boolean
29
+ error?: string
30
+ }
31
+
32
+ // ─── Component ────────────────────────────────────────────────────────────────
33
+
34
+ export const RoleSelectionPage: React.FC<RoleSelectionPageProps> = ({
35
+ pageTitle = 'Add User',
36
+ userName,
37
+ roles,
38
+ defaultRole,
39
+ submitLabel = 'Send Invitation',
40
+ onSubmit,
41
+ onBack,
42
+ onCancel,
43
+ isLoading = false,
44
+ error,
45
+ }) => {
46
+ const [selectedRole, setSelectedRole] = useState<string>(
47
+ defaultRole ?? roles[0]?.value ?? ''
48
+ )
49
+
50
+ return (
51
+ <div className="role-selection-page">
52
+ {/* ── Header ── */}
53
+ <header className="role-selection-page__header">
54
+ <h1 className="role-selection-page__title">{pageTitle}</h1>
55
+ {onCancel && (
56
+ <Button variant="secondary-soft" onClick={onCancel}>
57
+ Cancel
58
+ </Button>
59
+ )}
60
+ </header>
61
+
62
+ {/* ── Body ── */}
63
+ <div className="role-selection-page__body">
64
+ {onBack && (
65
+ <button className="role-selection-page__back" type="button" onClick={onBack}>
66
+ <ArrowLeftIcon />
67
+ Back
68
+ </button>
69
+ )}
70
+
71
+ {error && (
72
+ <div className="role-selection-page__error-banner" role="alert">
73
+ {error}
74
+ </div>
75
+ )}
76
+
77
+ <div className="role-selection-page__step-header">
78
+ <h2 className="role-selection-page__step-title">
79
+ What sort of user is {userName ? <strong>{userName}</strong> : 'this user'}?
80
+ </h2>
81
+ <p className="role-selection-page__step-desc">
82
+ Permissions can be customised after the user is created.
83
+ </p>
84
+ </div>
85
+
86
+ <div className="role-selection-page__roles" role="radiogroup" aria-label="Select role">
87
+ {roles.map((role) => (
88
+ <label
89
+ key={role.value}
90
+ className={[
91
+ 'role-selection-page__role-card',
92
+ selectedRole === role.value ? 'role-selection-page__role-card--selected' : '',
93
+ ]
94
+ .filter(Boolean)
95
+ .join(' ')}
96
+ >
97
+ <input
98
+ className="role-selection-page__role-input"
99
+ type="radio"
100
+ name="role"
101
+ value={role.value}
102
+ checked={selectedRole === role.value}
103
+ onChange={() => setSelectedRole(role.value)}
104
+ />
105
+ <div className="role-selection-page__role-content">
106
+ <span className="role-selection-page__role-label">{role.label}</span>
107
+ {role.description && (
108
+ <span className="role-selection-page__role-desc">{role.description}</span>
109
+ )}
110
+ </div>
111
+ <div className="role-selection-page__role-radio" aria-hidden="true" />
112
+ </label>
113
+ ))}
114
+ </div>
115
+
116
+ <Button
117
+ variant="primary"
118
+ onClick={() => onSubmit(selectedRole)}
119
+ isLoading={isLoading}
120
+ disabled={isLoading || !selectedRole}
121
+ >
122
+ {submitLabel}
123
+ </Button>
124
+ </div>
125
+ </div>
126
+ )
127
+ }
@@ -0,0 +1,2 @@
1
+ export { RoleSelectionPage } from './RoleSelectionPage'
2
+ export type { RoleSelectionPageProps, RoleOption } from './RoleSelectionPage'
@@ -0,0 +1,236 @@
1
+ @import '../../styles/index.scss';
2
+
3
+ .user-details-page {
4
+ display: flex;
5
+ flex-direction: column;
6
+ min-height: 100vh;
7
+ background: var(--surface-primary, #ffffff);
8
+
9
+ // ── Header ────────────────────────────────────────────────────────────────
10
+ &__header {
11
+ display: flex;
12
+ align-items: center;
13
+ justify-content: space-between;
14
+ padding: 16px 24px;
15
+ border-bottom: 1px solid var(--border-primary, #e8e9ef);
16
+ background: var(--surface-primary, #ffffff);
17
+ position: sticky;
18
+ top: 0;
19
+ z-index: 10;
20
+ }
21
+
22
+ &__title {
23
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
24
+ font-size: 18px;
25
+ font-weight: 700;
26
+ line-height: 24px;
27
+ color: var(--label-primary, #121e52);
28
+ margin: 0;
29
+ }
30
+
31
+ // ── Body ──────────────────────────────────────────────────────────────────
32
+ &__body {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 16px;
36
+ padding: 24px;
37
+ width: 100%;
38
+ max-width: 700px;
39
+ margin: 0 auto;
40
+ }
41
+
42
+ // ── Back button ───────────────────────────────────────────────────────────
43
+ &__back {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ gap: 6px;
47
+ background: none;
48
+ border: none;
49
+ cursor: pointer;
50
+ padding: 6px 8px;
51
+ border-radius: var(--radius-sm, 4px);
52
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
53
+ font-size: 14px;
54
+ font-weight: 500;
55
+ color: var(--label-action, #6200ee);
56
+ transition: background 0.15s ease;
57
+
58
+ &:hover {
59
+ background: var(--surface-action-soft, #f3e8ff);
60
+ }
61
+
62
+ svg path {
63
+ stroke: currentColor;
64
+ }
65
+ }
66
+
67
+ // ── Error banner ──────────────────────────────────────────────────────────
68
+ &__error-banner {
69
+ width: 100%;
70
+ padding: 12px 16px;
71
+ background: var(--surface-status-error-soft, #fef2f2);
72
+ border: 1px solid var(--border-status-error, #fecaca);
73
+ border-radius: var(--radius-md, 8px);
74
+ font-size: 14px;
75
+ color: var(--label-status-error, #ef4444);
76
+ }
77
+
78
+ // ── Step header ───────────────────────────────────────────────────────────
79
+ &__step-header {
80
+ display: flex;
81
+ flex-direction: column;
82
+ gap: 6px;
83
+ }
84
+
85
+ &__step-title {
86
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
87
+ font-size: 20px;
88
+ font-weight: 600;
89
+ color: var(--label-primary, #121e52);
90
+ margin: 0;
91
+ }
92
+
93
+ &__step-desc {
94
+ font-size: 14px;
95
+ color: var(--label-secondary, #626a90);
96
+ margin: 0;
97
+ }
98
+
99
+ // ── New user form ─────────────────────────────────────────────────────────
100
+ &__form {
101
+ display: flex;
102
+ flex-direction: column;
103
+ gap: 24px;
104
+ width: 100%;
105
+ }
106
+
107
+ &__fields {
108
+ display: flex;
109
+ flex-direction: column;
110
+ gap: 16px;
111
+ width: 100%;
112
+ }
113
+
114
+ // ── Existing user section ─────────────────────────────────────────────────
115
+ &__existing {
116
+ display: flex;
117
+ flex-direction: column;
118
+ gap: 24px;
119
+ width: 100%;
120
+ }
121
+
122
+ &__user-card {
123
+ display: flex;
124
+ align-items: center;
125
+ gap: 14px;
126
+ padding: 16px;
127
+ background: var(--surface-secondary, #f8f8fa);
128
+ border: 1px solid var(--border-primary, #e8e9ef);
129
+ border-radius: var(--radius-lg, 12px);
130
+ }
131
+
132
+ &__user-info {
133
+ display: flex;
134
+ flex-direction: column;
135
+ gap: 3px;
136
+ flex: 1;
137
+ }
138
+
139
+ &__user-name {
140
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
141
+ font-size: 15px;
142
+ font-weight: 600;
143
+ color: var(--label-primary, #121e52);
144
+ }
145
+
146
+ &__user-email {
147
+ font-size: 13px;
148
+ color: var(--label-secondary, #626a90);
149
+ }
150
+
151
+ &__user-number {
152
+ font-size: 12px;
153
+ color: var(--label-tertiary, #9ea4bf);
154
+ }
155
+
156
+ // ── Assignment list ───────────────────────────────────────────────────────
157
+ &__assignments {
158
+ display: flex;
159
+ flex-direction: column;
160
+ gap: 10px;
161
+ }
162
+
163
+ &__assignments-label {
164
+ font-size: 11px;
165
+ font-weight: 600;
166
+ text-transform: uppercase;
167
+ letter-spacing: 0.06em;
168
+ color: var(--label-secondary, #626a90);
169
+ margin: 0;
170
+ }
171
+
172
+ &__assignment-list {
173
+ list-style: none;
174
+ padding: 0;
175
+ margin: 0;
176
+ display: flex;
177
+ flex-direction: column;
178
+ gap: 6px;
179
+ }
180
+
181
+ &__assignment-item {
182
+ display: flex;
183
+ align-items: center;
184
+ gap: 8px;
185
+ padding: 10px 14px;
186
+ background: var(--surface-primary, #ffffff);
187
+ border: 1px solid var(--border-primary, #e8e9ef);
188
+ border-radius: var(--radius-md, 8px);
189
+ }
190
+
191
+ &__assignment-name {
192
+ font-size: 14px;
193
+ font-weight: 500;
194
+ color: var(--label-primary, #121e52);
195
+ flex: 1;
196
+ }
197
+
198
+ &__assignment-id {
199
+ font-size: 12px;
200
+ color: var(--label-tertiary, #9ea4bf);
201
+ }
202
+
203
+ &__assignment-role {
204
+ font-size: 12px;
205
+ font-weight: 500;
206
+ color: var(--label-secondary, #626a90);
207
+ padding: 2px 8px;
208
+ background: var(--surface-secondary, #f8f8fa);
209
+ border-radius: var(--radius-sm, 4px);
210
+ }
211
+
212
+ &__entity-badge {
213
+ flex-shrink: 0;
214
+ font-size: 10px;
215
+ font-weight: 700;
216
+ text-transform: uppercase;
217
+ letter-spacing: 0.05em;
218
+ padding: 2px 6px;
219
+ border-radius: var(--radius-sm, 4px);
220
+
221
+ &--venue {
222
+ color: var(--label-status-info, #0ea5e9);
223
+ background: var(--surface-status-info-soft, #e0f2fe);
224
+ }
225
+
226
+ &--company {
227
+ color: var(--label-status-warning, #f59e0b);
228
+ background: var(--surface-status-warning-soft, #fef3c7);
229
+ }
230
+
231
+ &--promoter {
232
+ color: var(--label-status-success, #10b981);
233
+ background: var(--surface-status-success-soft, #d1fae5);
234
+ }
235
+ }
236
+ }