@licklist/design 0.78.21 → 0.78.26

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 (186) hide show
  1. package/dist/assets/Trend-Down.svg +3 -0
  2. package/dist/assets/Trend-Up.svg +3 -0
  3. package/dist/auth/Authorizer.d.ts.map +1 -1
  4. package/dist/auth/Authorizer.js +47 -12
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +5 -0
  8. package/dist/v2/components/EntityHeader/EntityHeader.d.ts +13 -0
  9. package/dist/v2/components/EntityHeader/EntityHeader.d.ts.map +1 -0
  10. package/dist/v2/components/EntityHeader/EntityHeader.js +85 -0
  11. package/dist/v2/components/EntityHeader/EntityHeader.scss.js +6 -0
  12. package/dist/v2/components/EntityHeader/index.d.ts +2 -0
  13. package/dist/v2/components/EntityHeader/index.d.ts.map +1 -0
  14. package/dist/v2/components/NPSScore/NPSScore.d.ts +18 -0
  15. package/dist/v2/components/NPSScore/NPSScore.d.ts.map +1 -0
  16. package/dist/v2/components/NPSScore/index.d.ts +3 -0
  17. package/dist/v2/components/NPSScore/index.d.ts.map +1 -0
  18. package/dist/v2/components/Select/Select.d.ts +10 -0
  19. package/dist/v2/components/Select/Select.d.ts.map +1 -0
  20. package/dist/v2/components/Select/index.d.ts +3 -0
  21. package/dist/v2/components/Select/index.d.ts.map +1 -0
  22. package/dist/v2/components/Tooltip/Tooltip.d.ts +21 -0
  23. package/dist/v2/components/Tooltip/Tooltip.d.ts.map +1 -0
  24. package/dist/v2/components/Tooltip/Tooltip.js +103 -0
  25. package/dist/v2/components/Tooltip/Tooltip.scss.js +6 -0
  26. package/dist/v2/components/Tooltip/index.d.ts +2 -0
  27. package/dist/v2/components/Tooltip/index.d.ts.map +1 -0
  28. package/dist/v2/components/UserAvatar/UserAvatar.d.ts +12 -0
  29. package/dist/v2/components/UserAvatar/UserAvatar.d.ts.map +1 -0
  30. package/dist/v2/components/UserAvatar/UserAvatar.js +77 -0
  31. package/dist/v2/components/UserAvatar/UserAvatar.scss.js +6 -0
  32. package/dist/v2/components/UserAvatar/index.d.ts +2 -0
  33. package/dist/v2/components/UserAvatar/index.d.ts.map +1 -0
  34. package/dist/v2/components/UserPanel/UserPanel.d.ts +17 -0
  35. package/dist/v2/components/UserPanel/UserPanel.d.ts.map +1 -0
  36. package/dist/v2/components/UserPanel/UserPanel.js +144 -0
  37. package/dist/v2/components/UserPanel/UserPanel.scss.js +6 -0
  38. package/dist/v2/components/UserPanel/index.d.ts +3 -0
  39. package/dist/v2/components/UserPanel/index.d.ts.map +1 -0
  40. package/dist/v2/dashboard-analytics/blog-posts/Blog.d.ts +15 -0
  41. package/dist/v2/dashboard-analytics/blog-posts/Blog.d.ts.map +1 -0
  42. package/dist/v2/dashboard-analytics/blog-posts/index.d.ts +3 -0
  43. package/dist/v2/dashboard-analytics/blog-posts/index.d.ts.map +1 -0
  44. package/dist/v2/dashboard-analytics/chart/Chart.d.ts +21 -0
  45. package/dist/v2/dashboard-analytics/chart/Chart.d.ts.map +1 -0
  46. package/dist/v2/dashboard-analytics/chart/index.d.ts +3 -0
  47. package/dist/v2/dashboard-analytics/chart/index.d.ts.map +1 -0
  48. package/dist/v2/dashboard-analytics/dashboard/Dashboard.d.ts +57 -0
  49. package/dist/v2/dashboard-analytics/dashboard/Dashboard.d.ts.map +1 -0
  50. package/dist/v2/dashboard-analytics/dashboard/index.d.ts +3 -0
  51. package/dist/v2/dashboard-analytics/dashboard/index.d.ts.map +1 -0
  52. package/dist/v2/dashboard-analytics/index.d.ts +13 -0
  53. package/dist/v2/dashboard-analytics/index.d.ts.map +1 -0
  54. package/dist/v2/dashboard-analytics/metric-card/MetricCard.d.ts +17 -0
  55. package/dist/v2/dashboard-analytics/metric-card/MetricCard.d.ts.map +1 -0
  56. package/dist/v2/dashboard-analytics/metric-card/index.d.ts +3 -0
  57. package/dist/v2/dashboard-analytics/metric-card/index.d.ts.map +1 -0
  58. package/dist/v2/dashboard-analytics/venue-card/VenueCard.d.ts +12 -0
  59. package/dist/v2/dashboard-analytics/venue-card/VenueCard.d.ts.map +1 -0
  60. package/dist/v2/dashboard-analytics/venue-card/index.d.ts +3 -0
  61. package/dist/v2/dashboard-analytics/venue-card/index.d.ts.map +1 -0
  62. package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.d.ts +25 -0
  63. package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.d.ts.map +1 -0
  64. package/dist/v2/dashboard-analytics/venue-closed-card/index.d.ts +3 -0
  65. package/dist/v2/dashboard-analytics/venue-closed-card/index.d.ts.map +1 -0
  66. package/dist/v2/index.d.ts +11 -5
  67. package/dist/v2/index.d.ts.map +1 -1
  68. package/dist/v2/navigation/DashboardLayout/AdminSidebar.d.ts +10 -0
  69. package/dist/v2/navigation/DashboardLayout/AdminSidebar.d.ts.map +1 -0
  70. package/dist/v2/navigation/DashboardLayout/AdminSidebar.js +296 -0
  71. package/dist/v2/navigation/DashboardLayout/AdminSidebar.scss.js +6 -0
  72. package/dist/v2/navigation/DashboardLayout/DashboardFooter.d.ts +7 -0
  73. package/dist/v2/navigation/DashboardLayout/DashboardFooter.d.ts.map +1 -0
  74. package/dist/v2/navigation/DashboardLayout/DashboardFooter.js +34 -0
  75. package/dist/v2/navigation/DashboardLayout/DashboardFooter.scss.js +6 -0
  76. package/dist/v2/navigation/DashboardLayout/DashboardLayout.d.ts +42 -0
  77. package/dist/v2/navigation/DashboardLayout/DashboardLayout.d.ts.map +1 -0
  78. package/dist/v2/navigation/DashboardLayout/DashboardLayout.js +176 -0
  79. package/dist/v2/navigation/DashboardLayout/DashboardLayout.scss.js +6 -0
  80. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.d.ts +35 -0
  81. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.d.ts.map +1 -0
  82. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.js +366 -0
  83. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.scss.js +6 -0
  84. package/dist/v2/navigation/DashboardLayout/TopNavigation.d.ts +26 -0
  85. package/dist/v2/navigation/DashboardLayout/TopNavigation.d.ts.map +1 -0
  86. package/dist/v2/navigation/DashboardLayout/TopNavigation.js +360 -0
  87. package/dist/v2/navigation/DashboardLayout/TopNavigation.scss.js +6 -0
  88. package/dist/v2/navigation/DashboardLayout/assets/AdminLogo.png.js +3 -0
  89. package/dist/v2/navigation/DashboardLayout/assets/BookedLogo_Mark.png.js +3 -0
  90. package/dist/v2/navigation/DashboardLayout/index.d.ts +7 -0
  91. package/dist/v2/navigation/DashboardLayout/index.d.ts.map +1 -0
  92. package/package.json +5 -3
  93. package/src/assets/Trend-Down.svg +3 -0
  94. package/src/assets/Trend-Up.svg +3 -0
  95. package/src/auth/Authorizer.tsx +49 -20
  96. package/src/index.ts +2 -1
  97. package/src/v2/components/EntityHeader/EntityHeader.scss +133 -0
  98. package/src/v2/components/EntityHeader/EntityHeader.stories.tsx +103 -0
  99. package/src/v2/components/EntityHeader/EntityHeader.tsx +76 -0
  100. package/src/v2/components/EntityHeader/index.ts +1 -0
  101. package/src/v2/components/NPSScore/NPSScore.scss +330 -0
  102. package/src/v2/components/NPSScore/NPSScore.stories.tsx +29 -0
  103. package/src/v2/components/NPSScore/NPSScore.tsx +209 -0
  104. package/src/v2/components/NPSScore/index.ts +2 -0
  105. package/src/v2/components/Select/Select.scss +188 -0
  106. package/src/v2/components/Select/Select.stories.tsx +164 -0
  107. package/src/v2/components/Select/Select.tsx +56 -0
  108. package/src/v2/components/Select/index.ts +2 -0
  109. package/src/v2/components/Tooltip/Tooltip.scss +92 -0
  110. package/src/v2/components/Tooltip/Tooltip.stories.tsx +164 -0
  111. package/src/v2/components/Tooltip/Tooltip.tsx +64 -0
  112. package/src/v2/components/Tooltip/index.ts +8 -0
  113. package/src/v2/components/UserAvatar/UserAvatar.scss +62 -0
  114. package/src/v2/components/UserAvatar/UserAvatar.stories.tsx +94 -0
  115. package/src/v2/components/UserAvatar/UserAvatar.tsx +96 -0
  116. package/src/v2/components/UserAvatar/index.ts +1 -0
  117. package/src/v2/components/UserPanel/UserPanel.scss +195 -0
  118. package/src/v2/components/UserPanel/UserPanel.stories.tsx +66 -0
  119. package/src/v2/components/UserPanel/UserPanel.tsx +126 -0
  120. package/src/v2/components/UserPanel/index.ts +2 -0
  121. package/src/v2/dashboard-analytics/blog-posts/Blog.scss +92 -0
  122. package/src/v2/dashboard-analytics/blog-posts/Blog.stories.tsx +57 -0
  123. package/src/v2/dashboard-analytics/blog-posts/Blog.tsx +91 -0
  124. package/src/v2/dashboard-analytics/blog-posts/index.ts +2 -0
  125. package/src/v2/dashboard-analytics/chart/Chart.scss +424 -0
  126. package/src/v2/dashboard-analytics/chart/Chart.stories.tsx +157 -0
  127. package/src/v2/dashboard-analytics/chart/Chart.tsx +623 -0
  128. package/src/v2/dashboard-analytics/chart/index.ts +2 -0
  129. package/src/v2/dashboard-analytics/dashboard/Dashboard.scss +254 -0
  130. package/src/v2/dashboard-analytics/dashboard/Dashboard.stories.tsx +298 -0
  131. package/src/v2/dashboard-analytics/dashboard/Dashboard.tsx +248 -0
  132. package/src/v2/dashboard-analytics/dashboard/index.ts +2 -0
  133. package/src/v2/dashboard-analytics/index.ts +12 -0
  134. package/src/v2/dashboard-analytics/metric-card/MetricCard.scss +125 -0
  135. package/src/v2/dashboard-analytics/metric-card/MetricCard.stories.tsx +106 -0
  136. package/src/v2/dashboard-analytics/metric-card/MetricCard.tsx +72 -0
  137. package/src/v2/dashboard-analytics/metric-card/index.ts +2 -0
  138. package/src/v2/dashboard-analytics/venue-card/VenueCard.scss +112 -0
  139. package/src/v2/dashboard-analytics/venue-card/VenueCard.stories.tsx +40 -0
  140. package/src/v2/dashboard-analytics/venue-card/VenueCard.tsx +62 -0
  141. package/src/v2/dashboard-analytics/venue-card/index.ts +2 -0
  142. package/src/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.scss +129 -0
  143. package/src/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.stories.tsx +31 -0
  144. package/src/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.tsx +61 -0
  145. package/src/v2/dashboard-analytics/venue-closed-card/index.ts +2 -0
  146. package/src/v2/design-system/colors/ColorSystem.scss +439 -0
  147. package/src/v2/design-system/colors/ColorSystem.stories.tsx +730 -0
  148. package/src/v2/design-system/typography/Typography.scss +295 -0
  149. package/src/v2/design-system/typography/Typography.stories.tsx +109 -0
  150. package/src/v2/index.ts +43 -7
  151. package/src/v2/navigation/DashboardLayout/AdminSidebar.scss +207 -0
  152. package/src/v2/navigation/DashboardLayout/AdminSidebar.tsx +171 -0
  153. package/src/v2/navigation/DashboardLayout/DashboardFooter.scss +30 -0
  154. package/src/v2/navigation/DashboardLayout/DashboardFooter.tsx +25 -0
  155. package/src/v2/navigation/DashboardLayout/DashboardLayout.scss +91 -0
  156. package/src/v2/navigation/DashboardLayout/DashboardLayout.stories.tsx +370 -0
  157. package/src/v2/navigation/DashboardLayout/DashboardLayout.tsx +233 -0
  158. package/src/v2/navigation/DashboardLayout/ProviderSidebar.scss +271 -0
  159. package/src/v2/navigation/DashboardLayout/ProviderSidebar.tsx +266 -0
  160. package/src/v2/navigation/DashboardLayout/Sidebar.stories.tsx +220 -0
  161. package/src/v2/navigation/DashboardLayout/TopNavigation.scss +206 -0
  162. package/src/v2/navigation/DashboardLayout/TopNavigation.tsx +279 -0
  163. package/src/v2/navigation/DashboardLayout/assets/AdminLogo.png +0 -0
  164. package/src/v2/navigation/DashboardLayout/assets/BookedLogo_Mark.png +0 -0
  165. package/src/v2/navigation/DashboardLayout/index.ts +20 -0
  166. package/src/v2/styles/index.scss +0 -1
  167. package/src/v2/styles/tokens/_colors.scss +531 -98
  168. package/dist/v2/components/Colors/Colors.d.ts +0 -21
  169. package/dist/v2/components/Colors/Colors.d.ts.map +0 -1
  170. package/dist/v2/components/Colors/index.d.ts +0 -3
  171. package/dist/v2/components/Colors/index.d.ts.map +0 -1
  172. package/dist/v2/components/Typography/Typography.d.ts +0 -11
  173. package/dist/v2/components/Typography/Typography.d.ts.map +0 -1
  174. package/dist/v2/components/Typography/index.d.ts +0 -3
  175. package/dist/v2/components/Typography/index.d.ts.map +0 -1
  176. package/src/v2/components/Colors/Colors.scss +0 -64
  177. package/src/v2/components/Colors/Colors.stories.tsx +0 -143
  178. package/src/v2/components/Colors/Colors.tsx +0 -51
  179. package/src/v2/components/Colors/ColorsAliases.stories.tsx +0 -285
  180. package/src/v2/components/Colors/Sizes.stories.tsx +0 -141
  181. package/src/v2/components/Colors/index.ts +0 -2
  182. package/src/v2/components/Typography/Typography.scss +0 -72
  183. package/src/v2/components/Typography/Typography.stories.tsx +0 -266
  184. package/src/v2/components/Typography/Typography.tsx +0 -56
  185. package/src/v2/components/Typography/index.ts +0 -2
  186. package/src/v2/styles/tokens/_aliases.scss +0 -199
@@ -1,23 +1,31 @@
1
- import { ReactNode, useEffect, useState, useCallback } from 'react'
2
- import { matchPath, useLocation } from 'react-router-dom'
1
+ import { ReactNode, useEffect, useState, useCallback, useContext, useRef } from 'react'
2
+ import { matchPath, useLocation, useNavigate } from 'react-router-dom'
3
3
  import useUser from '@licklist/plugins/dist/context/user/hooks/useUser'
4
4
  import { ROUTES, MATCH_ROUTE_PATTERNS } from '@licklist/core/dist/Config'
5
5
  import useAuthApi from '@licklist/plugins/dist/hooks/Api/useAuthApi'
6
6
  import useAuth from '@licklist/plugins/dist/context/user/hooks/useAuth'
7
7
  import RouteService from '@licklist/plugins/dist/services/Route/RouteService'
8
+ import StorageContext from '@licklist/plugins/dist/context/app/StorageContext'
9
+ import JsonService from '@licklist/plugins/dist/services/Json/JsonService'
10
+ import { IAuth } from '@licklist/plugins/dist/types/context/user/IAuth'
8
11
  import { BlockLoader } from '../static/loader/BlockLoader'
9
12
 
10
13
  export interface AuthorizerProps {
11
14
  children?: ReactNode | ReactNode[]
12
15
  }
13
16
 
17
+ const AUTH_CONTEXT_KEY = 'auth'
18
+
14
19
  function Authorizer(props: AuthorizerProps) {
15
20
  const { children } = props
16
21
  const auth = useAuth()
17
22
  const user = useUser()
18
23
  const { useProfile } = useAuthApi()
24
+ const storage = useContext(StorageContext)
25
+ const isLoggingOut = useRef(false)
19
26
 
20
27
  const { pathname } = useLocation()
28
+ const navigate = useNavigate()
21
29
 
22
30
  // This will re-fetch user's profile
23
31
  const profile = useProfile()
@@ -40,6 +48,24 @@ function Authorizer(props: AuthorizerProps) {
40
48
  [],
41
49
  )
42
50
 
51
+ // Check auth on every route change - if storage was cleared, logout immediately
52
+ useEffect(() => {
53
+ if (isLoggingOut.current) return
54
+
55
+ const storedAuth = storage.get(AUTH_CONTEXT_KEY)
56
+ const parsedAuth = storedAuth ? JsonService.decode<IAuth>(storedAuth) : null
57
+
58
+ // If we have auth in memory but not in storage, session was cleared
59
+ if (auth.secrets !== null && !parsedAuth) {
60
+ isLoggingOut.current = true
61
+ auth.setSecrets(null)
62
+ user.setProfile(null)
63
+
64
+ const route = RouteService.getCurrentRoute()
65
+ navigate([ROUTES.LOGIN_PAGE, `returnUrl=${escape(route)}`].join('?'), { replace: true })
66
+ }
67
+ }, [pathname, auth.secrets, storage, navigate, auth, user])
68
+
43
69
  useEffect(() => {
44
70
  if (profile.isLoading || profile.isFetching) {
45
71
  return
@@ -54,38 +80,41 @@ function Authorizer(props: AuthorizerProps) {
54
80
  return
55
81
  }
56
82
 
57
- if (
58
- [
59
- ROUTES.LOGIN_PAGE,
60
- ROUTES.REGISTER_PAGE,
61
- ROUTES.PRIVACY_PAGE,
62
- ROUTES.TERMS_PAGE,
63
- ROUTES.PRIVACY_FACTS_PAGE,
64
- ROUTES.CHANGE_PASSWORD,
65
- ROUTES.FORGOT_PASSWORD,
66
- ROUTES.SSO_LOGIN,
67
- ROUTES.MAINTENANCE_PAGE,
68
- ...matchedPathPatternUrls(),
69
- ].includes(pathname)
70
- ) {
71
- setIsValidated(() => true)
83
+ const publicRoutes = [
84
+ ROUTES.LOGIN_PAGE,
85
+ ROUTES.REGISTER_PAGE,
86
+ ROUTES.PRIVACY_PAGE,
87
+ ROUTES.TERMS_PAGE,
88
+ ROUTES.PRIVACY_FACTS_PAGE,
89
+ ROUTES.CHANGE_PASSWORD,
90
+ ROUTES.FORGOT_PASSWORD,
91
+ ROUTES.SSO_LOGIN,
92
+ ROUTES.MAINTENANCE_PAGE,
93
+ ...matchedPathPatternUrls(),
94
+ ]
95
+
96
+ // If we're on a public route (e.g. /login), mark as validated and never redirect
97
+ if (publicRoutes.includes(pathname)) {
98
+ setIsValidated(true)
72
99
  return
73
100
  }
74
101
 
75
102
  const route = RouteService.getCurrentRoute()
76
103
 
77
- RouteService.redirectTo(
78
- [ROUTES.MAINTENANCE_PAGE, `returnUrl=${escape(route)}`].join('?'),
104
+ navigate(
105
+ [ROUTES.LOGIN_PAGE, `returnUrl=${escape(route)}`].join('?'),
106
+ { replace: true },
79
107
  )
80
108
  }, [
81
109
  auth.secrets,
82
110
  user.profile,
83
111
  profile.data,
84
- matchedPathPatternUrls,
85
112
  profile.isError,
86
113
  profile.isLoading,
87
114
  profile.isFetching,
88
115
  pathname,
116
+ matchedPathPatternUrls,
117
+ navigate,
89
118
  ])
90
119
 
91
120
  if (profile.isFetching || profile.isLoading || !isValidated)
package/src/index.ts CHANGED
@@ -45,4 +45,5 @@ export * from './fullscreen-loader'
45
45
  export * from './pages'
46
46
  export { default as RadioButton } from './customRadioButton/RadioButton'
47
47
  export * from './PageNotFound'
48
- export * from './UnderMaintenance'
48
+ export * from './UnderMaintenance'
49
+ export * from './v2/navigation/DashboardLayout'
@@ -0,0 +1,133 @@
1
+ .entity-header {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 8px;
5
+ padding: 8px;
6
+ border-radius: 8px;
7
+ background: var(--surfaces-main-surface-secondary, #F4F4F7);
8
+ cursor: pointer;
9
+ transition: background 0.2s ease;
10
+ width: 100%;
11
+ box-sizing: border-box;
12
+
13
+ &:hover {
14
+ background: var(--surfaces-main-surface-secondary-hover, #ECEDF2);
15
+
16
+ .entity-header__badge {
17
+ background: var(--surfaces-main-surface-tertiary-hover, #FFFFFF);
18
+ }
19
+ }
20
+
21
+ &:active {
22
+ background: var(--surfaces-main-surface-secondary-pressed, #E4E5EC);
23
+ }
24
+
25
+ &--collapsed {
26
+ justify-content: center;
27
+ }
28
+
29
+ &__avatar {
30
+ flex-shrink: 0;
31
+ border-radius: 50%;
32
+ overflow: hidden;
33
+ position: relative;
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ }
38
+
39
+ &__image {
40
+ width: 100%;
41
+ height: 100%;
42
+ object-fit: cover;
43
+ }
44
+
45
+ &__placeholder {
46
+ width: 100%;
47
+ height: 100%;
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ position: relative;
52
+
53
+ svg {
54
+ position: absolute;
55
+ top: 0;
56
+ left: 0;
57
+ }
58
+
59
+ span {
60
+ font-family: var(--font-family-sans);
61
+ font-weight: 700;
62
+ color: var(--labels-main-label-secondary, #626A90);
63
+ position: relative;
64
+ z-index: 1;
65
+ }
66
+ }
67
+
68
+ &__text {
69
+ display: flex;
70
+ flex-direction: column;
71
+ flex: 1;
72
+ gap: 4px;
73
+ min-width: 0;
74
+ }
75
+
76
+ &__name {
77
+ margin: 0;
78
+ font-family: var(--font-family-sans);
79
+ font-size: 15px;
80
+ font-weight: 600;
81
+ line-height: 18px;
82
+ color: var(--labels-main-label-primary, #121E52);
83
+ white-space: nowrap;
84
+ overflow: hidden;
85
+ text-overflow: ellipsis;
86
+ }
87
+
88
+ &__badge {
89
+ display: inline-flex;
90
+ align-items: center;
91
+ justify-content: center;
92
+ padding: 4px 8px;
93
+ background: var(--surfaces-main-surface-tertiary, #E8E9EF);
94
+ border-radius: 8px;
95
+ width: fit-content;
96
+ transition: background 0.2s ease;
97
+
98
+ span {
99
+ font-family: var(--font-family-mono);
100
+ font-size: 10px;
101
+ font-weight: 600;
102
+ line-height: 12px;
103
+ color: var(--labels-main-label-secondary, #626A90);
104
+ white-space: nowrap;
105
+ }
106
+ }
107
+
108
+ &--sm {
109
+ gap: 8px;
110
+
111
+ .entity-header__name {
112
+ font-size: 13px;
113
+ line-height: 16px;
114
+ }
115
+
116
+ .entity-header__badge span {
117
+ font-size: 9px;
118
+ }
119
+ }
120
+
121
+ &--lg {
122
+ gap: 16px;
123
+
124
+ .entity-header__name {
125
+ font-size: 18px;
126
+ line-height: 24px;
127
+ }
128
+
129
+ .entity-header__badge span {
130
+ font-size: 11px;
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,103 @@
1
+ import { Meta, StoryObj } from '@storybook/react'
2
+ import { EntityHeader } from './EntityHeader'
3
+
4
+ export default {
5
+ title: 'v2/Components/EntityHeader',
6
+ component: EntityHeader,
7
+ argTypes: {
8
+ name: { control: 'text' },
9
+ id: { control: 'text' },
10
+ idLabel: { control: 'text' },
11
+ imageUrl: { control: 'text' },
12
+ size: { control: 'select', options: ['sm', 'md', 'lg'] },
13
+ collapsed: { control: 'boolean' },
14
+ },
15
+ parameters: {
16
+ layout: 'centered',
17
+ },
18
+ } as Meta<typeof EntityHeader>
19
+
20
+ type Story = StoryObj<typeof EntityHeader>
21
+
22
+ export const Default: Story = {
23
+ args: {
24
+ name: "Sharky's Soft Play",
25
+ id: '01',
26
+ idLabel: 'Venue ID',
27
+ size: 'md',
28
+ collapsed: false,
29
+ },
30
+ }
31
+
32
+ export const WithImage: Story = {
33
+ args: {
34
+ name: "Sharky's Soft Play",
35
+ id: '01',
36
+ idLabel: 'Venue ID',
37
+ imageUrl: 'https://i.pravatar.cc/150?img=12',
38
+ size: 'md',
39
+ },
40
+ }
41
+
42
+ export const Collapsed: Story = {
43
+ args: {
44
+ name: "Sharky's Soft Play",
45
+ id: '01',
46
+ idLabel: 'Venue ID',
47
+ size: 'md',
48
+ collapsed: true,
49
+ },
50
+ }
51
+
52
+ export const Small: Story = {
53
+ args: {
54
+ name: "Sharky's Soft Play",
55
+ id: '01',
56
+ idLabel: 'Venue ID',
57
+ size: 'sm',
58
+ },
59
+ }
60
+
61
+ export const Large: Story = {
62
+ args: {
63
+ name: "Sharky's Soft Play",
64
+ id: '01',
65
+ idLabel: 'Venue ID',
66
+ size: 'lg',
67
+ },
68
+ }
69
+
70
+ export const ProviderId: Story = {
71
+ args: {
72
+ name: 'Entertainment Group',
73
+ id: 'P-456',
74
+ idLabel: 'Provider ID',
75
+ size: 'md',
76
+ },
77
+ }
78
+
79
+ export const CompanyId: Story = {
80
+ args: {
81
+ name: 'Acme Corporation',
82
+ id: 'C-789',
83
+ idLabel: 'Company ID',
84
+ size: 'md',
85
+ },
86
+ }
87
+
88
+ export const NoId: Story = {
89
+ args: {
90
+ name: "Sharky's Soft Play",
91
+ size: 'md',
92
+ },
93
+ }
94
+
95
+ export const AllSizes: Story = {
96
+ render: () => (
97
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
98
+ <EntityHeader name="Sharky's Soft Play" id="01" idLabel="Venue ID" size="sm" />
99
+ <EntityHeader name="Sharky's Soft Play" id="01" idLabel="Venue ID" size="md" />
100
+ <EntityHeader name="Sharky's Soft Play" id="01" idLabel="Venue ID" size="lg" />
101
+ </div>
102
+ ),
103
+ }
@@ -0,0 +1,76 @@
1
+ import React from 'react'
2
+ import './EntityHeader.scss'
3
+
4
+ export interface EntityHeaderProps {
5
+ name: string
6
+ id?: string
7
+ idLabel?: string
8
+ imageUrl?: string
9
+ size?: 'sm' | 'md' | 'lg'
10
+ collapsed?: boolean
11
+ className?: string
12
+ }
13
+
14
+ export const EntityHeader: React.FC<EntityHeaderProps> = ({
15
+ name,
16
+ id,
17
+ idLabel = 'ID',
18
+ imageUrl,
19
+ size = 'md',
20
+ collapsed = false,
21
+ className = '',
22
+ }) => {
23
+ const sizeMap = {
24
+ sm: 32,
25
+ md: 47,
26
+ lg: 64,
27
+ }
28
+
29
+ const fontSizeMap = {
30
+ sm: 12,
31
+ md: 18,
32
+ lg: 24,
33
+ }
34
+
35
+ const dimension = sizeMap[size]
36
+ const initialFontSize = fontSizeMap[size]
37
+ const circleRadius = (dimension / 2) - 1 // Account for stroke width
38
+
39
+ return (
40
+ <div className={`entity-header entity-header--${size} ${collapsed ? 'entity-header--collapsed' : ''} ${className}`.trim()}>
41
+ <div
42
+ className="entity-header__avatar"
43
+ style={{ width: dimension, height: dimension }}
44
+ >
45
+ {imageUrl ? (
46
+ <img src={imageUrl} alt={name} className="entity-header__image" />
47
+ ) : (
48
+ <div className="entity-header__placeholder">
49
+ <svg width={dimension} height={dimension} viewBox={`0 0 ${dimension} ${dimension}`} fill="none">
50
+ <circle
51
+ cx={dimension / 2}
52
+ cy={dimension / 2}
53
+ r={circleRadius}
54
+ fill="var(--fills-main-fill-secondary, #626A90)"
55
+ fillOpacity="0.2"
56
+ stroke="var(--fills-main-fill-secondary, #626A90)"
57
+ strokeWidth="2"
58
+ />
59
+ </svg>
60
+ <span style={{ fontSize: initialFontSize }}>{name?.[0]?.toUpperCase() || 'S'}</span>
61
+ </div>
62
+ )}
63
+ </div>
64
+ {!collapsed && (
65
+ <div className="entity-header__text">
66
+ <h3 className="entity-header__name">{name}</h3>
67
+ {id && (
68
+ <div className="entity-header__badge">
69
+ <span>{idLabel}: {id}</span>
70
+ </div>
71
+ )}
72
+ </div>
73
+ )}
74
+ </div>
75
+ )
76
+ }
@@ -0,0 +1 @@
1
+ export { EntityHeader, type EntityHeaderProps } from './EntityHeader'