@strapi/admin 5.53.0 → 5.55.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.
Files changed (183) hide show
  1. package/dist/admin/admin/src/App.js +1 -1
  2. package/dist/admin/admin/src/App.js.map +1 -1
  3. package/dist/admin/admin/src/App.mjs +1 -1
  4. package/dist/admin/admin/src/App.mjs.map +1 -1
  5. package/dist/admin/admin/src/components/DismissibleBanner.js +60 -0
  6. package/dist/admin/admin/src/components/DismissibleBanner.js.map +1 -0
  7. package/dist/admin/admin/src/components/DismissibleBanner.mjs +58 -0
  8. package/dist/admin/admin/src/components/DismissibleBanner.mjs.map +1 -0
  9. package/dist/admin/admin/src/components/Form.js +11 -2
  10. package/dist/admin/admin/src/components/Form.js.map +1 -1
  11. package/dist/admin/admin/src/components/Form.mjs +11 -2
  12. package/dist/admin/admin/src/components/Form.mjs.map +1 -1
  13. package/dist/admin/admin/src/components/FormInputs/DateTime.js +1 -1
  14. package/dist/admin/admin/src/components/FormInputs/DateTime.js.map +1 -1
  15. package/dist/admin/admin/src/components/FormInputs/DateTime.mjs +1 -1
  16. package/dist/admin/admin/src/components/FormInputs/DateTime.mjs.map +1 -1
  17. package/dist/admin/admin/src/components/FormInputs/Time.js +1 -1
  18. package/dist/admin/admin/src/components/FormInputs/Time.js.map +1 -1
  19. package/dist/admin/admin/src/components/FormInputs/Time.mjs +1 -1
  20. package/dist/admin/admin/src/components/FormInputs/Time.mjs.map +1 -1
  21. package/dist/admin/admin/src/components/LanguageProvider.js +35 -1
  22. package/dist/admin/admin/src/components/LanguageProvider.js.map +1 -1
  23. package/dist/admin/admin/src/components/LanguageProvider.mjs +17 -2
  24. package/dist/admin/admin/src/components/LanguageProvider.mjs.map +1 -1
  25. package/dist/admin/admin/src/components/MainNav/NavUser.js +1 -2
  26. package/dist/admin/admin/src/components/MainNav/NavUser.js.map +1 -1
  27. package/dist/admin/admin/src/components/MainNav/NavUser.mjs +1 -2
  28. package/dist/admin/admin/src/components/MainNav/NavUser.mjs.map +1 -1
  29. package/dist/admin/admin/src/components/MediaLibraryBanner.js +85 -0
  30. package/dist/admin/admin/src/components/MediaLibraryBanner.js.map +1 -0
  31. package/dist/admin/admin/src/components/MediaLibraryBanner.mjs +83 -0
  32. package/dist/admin/admin/src/components/MediaLibraryBanner.mjs.map +1 -0
  33. package/dist/admin/admin/src/components/Providers.js +6 -6
  34. package/dist/admin/admin/src/components/Providers.js.map +1 -1
  35. package/dist/admin/admin/src/components/Providers.mjs +6 -6
  36. package/dist/admin/admin/src/components/Providers.mjs.map +1 -1
  37. package/dist/admin/admin/src/components/SubNav.js +113 -35
  38. package/dist/admin/admin/src/components/SubNav.js.map +1 -1
  39. package/dist/admin/admin/src/components/SubNav.mjs +115 -37
  40. package/dist/admin/admin/src/components/SubNav.mjs.map +1 -1
  41. package/dist/admin/admin/src/components/SubNavFolder.js +188 -0
  42. package/dist/admin/admin/src/components/SubNavFolder.js.map +1 -0
  43. package/dist/admin/admin/src/components/SubNavFolder.mjs +186 -0
  44. package/dist/admin/admin/src/components/SubNavFolder.mjs.map +1 -0
  45. package/dist/admin/admin/src/components/UpsellBanner.js +56 -86
  46. package/dist/admin/admin/src/components/UpsellBanner.js.map +1 -1
  47. package/dist/admin/admin/src/components/UpsellBanner.mjs +58 -88
  48. package/dist/admin/admin/src/components/UpsellBanner.mjs.map +1 -1
  49. package/dist/admin/admin/src/core/store/configure.js +14 -2
  50. package/dist/admin/admin/src/core/store/configure.js.map +1 -1
  51. package/dist/admin/admin/src/core/store/configure.mjs +14 -2
  52. package/dist/admin/admin/src/core/store/configure.mjs.map +1 -1
  53. package/dist/admin/admin/src/core/store/hooks.mjs +1 -1
  54. package/dist/admin/admin/src/features/Auth.js +162 -46
  55. package/dist/admin/admin/src/features/Auth.js.map +1 -1
  56. package/dist/admin/admin/src/features/Auth.mjs +164 -48
  57. package/dist/admin/admin/src/features/Auth.mjs.map +1 -1
  58. package/dist/admin/admin/src/features/Tracking.js.map +1 -1
  59. package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
  60. package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.js +19 -0
  61. package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.js.map +1 -0
  62. package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.mjs +17 -0
  63. package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.mjs.map +1 -0
  64. package/dist/admin/admin/src/hooks/{useIdleSessionLogout.js → useSessionKeepalive.js} +34 -27
  65. package/dist/admin/admin/src/hooks/useSessionKeepalive.js.map +1 -0
  66. package/dist/admin/admin/src/hooks/{useIdleSessionLogout.mjs → useSessionKeepalive.mjs} +34 -27
  67. package/dist/admin/admin/src/hooks/useSessionKeepalive.mjs.map +1 -0
  68. package/dist/admin/admin/src/layouts/AuthenticatedLayout.js +2 -0
  69. package/dist/admin/admin/src/layouts/AuthenticatedLayout.js.map +1 -1
  70. package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs +2 -0
  71. package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs.map +1 -1
  72. package/dist/admin/admin/src/pages/SessionsPage.js +2 -5
  73. package/dist/admin/admin/src/pages/SessionsPage.js.map +1 -1
  74. package/dist/admin/admin/src/pages/SessionsPage.mjs +2 -5
  75. package/dist/admin/admin/src/pages/SessionsPage.mjs.map +1 -1
  76. package/dist/admin/admin/src/render.js +6 -1
  77. package/dist/admin/admin/src/render.js.map +1 -1
  78. package/dist/admin/admin/src/render.mjs +6 -1
  79. package/dist/admin/admin/src/render.mjs.map +1 -1
  80. package/dist/admin/admin/src/translations/en.json.js +16 -0
  81. package/dist/admin/admin/src/translations/en.json.js.map +1 -1
  82. package/dist/admin/admin/src/translations/en.json.mjs +16 -0
  83. package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
  84. package/dist/admin/admin/src/utils/baseQuery.js +3 -13
  85. package/dist/admin/admin/src/utils/baseQuery.js.map +1 -1
  86. package/dist/admin/admin/src/utils/baseQuery.mjs +3 -13
  87. package/dist/admin/admin/src/utils/baseQuery.mjs.map +1 -1
  88. package/dist/admin/admin/src/utils/getFetchClient.js +34 -5
  89. package/dist/admin/admin/src/utils/getFetchClient.js.map +1 -1
  90. package/dist/admin/admin/src/utils/getFetchClient.mjs +34 -6
  91. package/dist/admin/admin/src/utils/getFetchClient.mjs.map +1 -1
  92. package/dist/admin/admin/src/utils/unsavedChangesRegistry.js +25 -0
  93. package/dist/admin/admin/src/utils/unsavedChangesRegistry.js.map +1 -0
  94. package/dist/admin/admin/src/utils/unsavedChangesRegistry.mjs +22 -0
  95. package/dist/admin/admin/src/utils/unsavedChangesRegistry.mjs.map +1 -0
  96. package/dist/admin/admin/tests/utils.js +14 -14
  97. package/dist/admin/admin/tests/utils.js.map +1 -1
  98. package/dist/admin/admin/tests/utils.mjs +14 -14
  99. package/dist/admin/admin/tests/utils.mjs.map +1 -1
  100. package/dist/admin/ee/admin/src/hooks/useAIAvailability.js +1 -6
  101. package/dist/admin/ee/admin/src/hooks/useAIAvailability.js.map +1 -1
  102. package/dist/admin/ee/admin/src/hooks/useAIAvailability.mjs +1 -6
  103. package/dist/admin/ee/admin/src/hooks/useAIAvailability.mjs.map +1 -1
  104. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.js +7 -1
  105. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.js.map +1 -1
  106. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.mjs +7 -1
  107. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.mjs.map +1 -1
  108. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js +9 -1
  109. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js.map +1 -1
  110. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs +9 -1
  111. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs.map +1 -1
  112. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.js +0 -4
  113. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.js.map +1 -1
  114. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.mjs +0 -4
  115. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.mjs.map +1 -1
  116. package/dist/admin/index.js +1 -0
  117. package/dist/admin/index.js.map +1 -1
  118. package/dist/admin/index.mjs +1 -1
  119. package/dist/admin/src/components/DismissibleBanner.d.ts +8 -0
  120. package/dist/admin/src/components/MediaLibraryBanner.d.ts +2 -0
  121. package/dist/admin/src/components/SubNav.d.ts +27 -8
  122. package/dist/admin/src/components/SubNavFolder.d.ts +15 -0
  123. package/dist/admin/src/features/Tracking.d.ts +2 -1
  124. package/dist/admin/src/hooks/useRegisterUnsavedChanges.d.ts +6 -0
  125. package/dist/admin/src/hooks/useSessionKeepalive.d.ts +88 -0
  126. package/dist/admin/src/services/admin.d.ts +1 -0
  127. package/dist/admin/src/utils/getFetchClient.d.ts +14 -6
  128. package/dist/admin/src/utils/unsavedChangesRegistry.d.ts +11 -0
  129. package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.d.ts +8 -0
  130. package/dist/ee/server/src/controllers/admin.d.ts.map +1 -1
  131. package/dist/ee/server/src/index.d.ts.map +1 -1
  132. package/dist/server/ee/server/src/controllers/admin.js +1 -5
  133. package/dist/server/ee/server/src/controllers/admin.js.map +1 -1
  134. package/dist/server/ee/server/src/controllers/admin.mjs +1 -5
  135. package/dist/server/ee/server/src/controllers/admin.mjs.map +1 -1
  136. package/dist/server/ee/server/src/index.js +2 -0
  137. package/dist/server/ee/server/src/index.js.map +1 -1
  138. package/dist/server/ee/server/src/index.mjs +2 -0
  139. package/dist/server/ee/server/src/index.mjs.map +1 -1
  140. package/dist/server/server/src/ai/controllers/ai.js +3 -3
  141. package/dist/server/server/src/ai/controllers/ai.js.map +1 -1
  142. package/dist/server/server/src/ai/controllers/ai.mjs +3 -3
  143. package/dist/server/server/src/ai/controllers/ai.mjs.map +1 -1
  144. package/dist/server/server/src/ai/services/ai.js +37 -12
  145. package/dist/server/server/src/ai/services/ai.js.map +1 -1
  146. package/dist/server/server/src/ai/services/ai.mjs +37 -12
  147. package/dist/server/server/src/ai/services/ai.mjs.map +1 -1
  148. package/dist/server/server/src/audit-logs/tokens.js +106 -0
  149. package/dist/server/server/src/audit-logs/tokens.js.map +1 -0
  150. package/dist/server/server/src/audit-logs/tokens.mjs +99 -0
  151. package/dist/server/server/src/audit-logs/tokens.mjs.map +1 -0
  152. package/dist/server/server/src/controllers/admin.js +10 -1
  153. package/dist/server/server/src/controllers/admin.js.map +1 -1
  154. package/dist/server/server/src/controllers/admin.mjs +10 -1
  155. package/dist/server/server/src/controllers/admin.mjs.map +1 -1
  156. package/dist/server/server/src/services/api-token.js +106 -4
  157. package/dist/server/server/src/services/api-token.js.map +1 -1
  158. package/dist/server/server/src/services/api-token.mjs +107 -5
  159. package/dist/server/server/src/services/api-token.mjs.map +1 -1
  160. package/dist/server/server/src/services/transfer/token.js +56 -4
  161. package/dist/server/server/src/services/transfer/token.js.map +1 -1
  162. package/dist/server/server/src/services/transfer/token.mjs +57 -5
  163. package/dist/server/server/src/services/transfer/token.mjs.map +1 -1
  164. package/dist/server/src/ai/services/ai.d.ts +3 -1
  165. package/dist/server/src/ai/services/ai.d.ts.map +1 -1
  166. package/dist/server/src/audit-logs/tokens.d.ts +86 -0
  167. package/dist/server/src/audit-logs/tokens.d.ts.map +1 -0
  168. package/dist/server/src/controllers/admin.d.ts +1 -0
  169. package/dist/server/src/controllers/admin.d.ts.map +1 -1
  170. package/dist/server/src/controllers/index.d.ts +1 -0
  171. package/dist/server/src/controllers/index.d.ts.map +1 -1
  172. package/dist/server/src/index.d.ts +1 -0
  173. package/dist/server/src/index.d.ts.map +1 -1
  174. package/dist/server/src/services/api-token.d.ts.map +1 -1
  175. package/dist/server/src/services/transfer/token.d.ts.map +1 -1
  176. package/dist/shared/contracts/admin.d.ts +1 -0
  177. package/dist/shared/contracts/admin.d.ts.map +1 -1
  178. package/dist/shared/contracts/shared.d.ts +1 -0
  179. package/dist/shared/contracts/shared.d.ts.map +1 -1
  180. package/package.json +7 -7
  181. package/dist/admin/admin/src/hooks/useIdleSessionLogout.js.map +0 -1
  182. package/dist/admin/admin/src/hooks/useIdleSessionLogout.mjs.map +0 -1
  183. package/dist/admin/src/hooks/useIdleSessionLogout.d.ts +0 -87
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubNavFolder.js","sources":["../../../../../admin/src/components/SubNavFolder.tsx"],"sourcesContent":["import { useCallback, useId, useRef, useState } from 'react';\n\nimport { Box, Flex, Tooltip, Typography } from '@strapi/design-system';\nimport { ChevronDown } from '@strapi/icons';\nimport { styled } from 'styled-components';\n\nconst ANIMATION_DURATION = '0.5s';\nconst COLLAPSE_EASING = 'cubic-bezier(0, 1, 0, 1)';\n\ninterface SubNavFolderProps {\n label: string;\n depth?: number;\n open?: boolean;\n defaultOpen?: boolean;\n onToggle?: (open: boolean) => void;\n endAction?: React.ReactNode;\n /** Ref attached to the row element used as a drag-and-drop drop target. */\n rowRef?: React.Ref<HTMLDivElement>;\n isDropTarget?: boolean;\n children?: React.ReactNode;\n}\n\nconst FolderRow = styled(Flex)<{ $depth: number; $isDropTarget?: boolean }>`\n border-radius: ${({ theme }) => theme.borderRadius};\n\n padding-right: ${({ theme }) => theme.spaces[3]};\n\n padding-left: ${({ theme, $depth }) =>\n `calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};\n\n background-color: ${({ $isDropTarget, theme }) =>\n $isDropTarget ? theme.colors.primary100 : 'transparent'};\n outline: ${({ $isDropTarget, theme }) =>\n $isDropTarget ? `1px solid ${theme.colors.primary600}` : 'none'};\n outline-offset: -1px;\n\n &:hover {\n background-color: ${({ $isDropTarget, theme }) =>\n $isDropTarget ? theme.colors.primary100 : theme.colors.neutral100};\n }\n`;\n\nconst ToggleButton = styled.button`\n gap: ${({ theme }) => theme.spaces[2]};\n align-items: center;\n display: flex;\n flex: 1;\n\n padding-block: ${({ theme }) => theme.spaces[2]};\n padding-inline: 0;\n\n min-width: 0;\n\n background: transparent;\n border: none;\n\n text-align: left;\n cursor: pointer;\n\n &:focus-visible {\n outline-offset: -2px;\n }\n`;\n\nconst EndActionWrapper = styled(Flex)`\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 0.1s ease-out;\n\n ${FolderRow}:hover &,\n ${FolderRow}:focus-within & {\n opacity: 1;\n }\n`;\n\nconst Collapsible = styled.div<{ $open: boolean }>`\n grid-template-rows: ${({ $open }) => ($open ? '1fr' : '0fr')};\n display: grid;\n\n transition: grid-template-rows ${ANIMATION_DURATION} ${COLLAPSE_EASING};\n`;\n\nconst CollapsibleInner = styled.div`\n overflow: hidden;\n min-height: 0;\n`;\n\ninterface FolderViewProps {\n rowRef?: React.Ref<HTMLDivElement>;\n endAction?: React.ReactNode;\n children?: React.ReactNode;\n onToggleClick: () => void;\n isDropTarget?: boolean;\n label: string;\n depth: number;\n open: boolean;\n}\n\nconst FolderView = ({\n onToggleClick,\n isDropTarget,\n endAction,\n children,\n rowRef,\n label,\n depth,\n open,\n}: FolderViewProps) => {\n const listId = useId();\n\n const [isLabelTruncated, setIsLabelTruncated] = useState(false);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n\n // A callback ref (rather than useRef + useEffect) so measurement survives the label\n // element remounting when it moves in and out of the Tooltip wrapper below.\n const measureLabelRef = useCallback((node: HTMLElement | null) => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n resizeObserverRef.current = null;\n }\n\n if (!node) {\n return;\n }\n\n const measure = () => {\n setIsLabelTruncated(node.scrollWidth > node.clientWidth);\n };\n\n measure();\n\n if (typeof ResizeObserver === 'undefined') {\n return;\n }\n\n resizeObserverRef.current = new ResizeObserver(measure);\n resizeObserverRef.current.observe(node);\n }, []);\n\n const applyInertWhenClosed = useCallback(\n (node: HTMLDivElement | null) => {\n if (!node) {\n return;\n }\n\n if (open) {\n node.removeAttribute('inert');\n } else {\n node.setAttribute('inert', '');\n }\n },\n [open]\n );\n\n const labelTypography = (\n <Typography\n textColor=\"neutral800\"\n fontWeight=\"semiBold\"\n ref={measureLabelRef}\n overflow=\"hidden\"\n tag=\"span\"\n style={{ flex: 1, minWidth: 0, textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n >\n {label}\n </Typography>\n );\n\n return (\n <Box>\n <FolderRow ref={rowRef} $depth={depth} $isDropTarget={isDropTarget} alignItems=\"center\">\n <ToggleButton\n onClick={onToggleClick}\n aria-controls={listId}\n aria-expanded={open}\n type=\"button\"\n >\n <ChevronDown\n fill=\"neutral500\"\n aria-hidden\n style={{\n transform: `rotate(${open ? '0deg' : '-90deg'})`,\n transition: `transform ${ANIMATION_DURATION}`,\n flexShrink: 0,\n }}\n />\n {isLabelTruncated ? <Tooltip label={label}>{labelTypography}</Tooltip> : labelTypography}\n </ToggleButton>\n {endAction != null && (\n <EndActionWrapper gap={2} alignItems=\"center\">\n {endAction}\n </EndActionWrapper>\n )}\n </FolderRow>\n <Collapsible $open={open} id={listId}>\n <CollapsibleInner ref={applyInertWhenClosed}>{children}</CollapsibleInner>\n </Collapsible>\n </Box>\n );\n};\n\nconst SubNavFolder = ({\n defaultOpen = false,\n open: openProp,\n isDropTarget,\n endAction,\n children,\n onToggle,\n rowRef,\n label,\n depth = 0,\n}: SubNavFolderProps) => {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n\n const isControlled = openProp !== undefined;\n const open = isControlled ? openProp : uncontrolledOpen;\n\n const handleToggleClick = () => {\n const next = !open;\n\n if (!isControlled) {\n setUncontrolledOpen(next);\n }\n\n onToggle?.(next);\n };\n\n return (\n <FolderView\n onToggleClick={handleToggleClick}\n isDropTarget={isDropTarget}\n endAction={endAction}\n rowRef={rowRef}\n label={label}\n depth={depth}\n open={open}\n >\n {children}\n </FolderView>\n );\n};\n\nexport { SubNavFolder };\nexport type { SubNavFolderProps };\n"],"names":["ANIMATION_DURATION","COLLAPSE_EASING","FolderRow","styled","Flex","theme","borderRadius","spaces","$depth","$isDropTarget","colors","primary100","primary600","neutral100","ToggleButton","button","EndActionWrapper","Collapsible","div","$open","CollapsibleInner","FolderView","onToggleClick","isDropTarget","endAction","children","rowRef","label","depth","open","listId","useId","isLabelTruncated","setIsLabelTruncated","useState","resizeObserverRef","useRef","measureLabelRef","useCallback","node","current","disconnect","measure","scrollWidth","clientWidth","ResizeObserver","observe","applyInertWhenClosed","removeAttribute","setAttribute","labelTypography","_jsx","Typography","textColor","fontWeight","ref","overflow","tag","style","flex","minWidth","textOverflow","whiteSpace","_jsxs","Box","alignItems","onClick","aria-controls","aria-expanded","type","ChevronDown","fill","aria-hidden","transform","transition","flexShrink","Tooltip","gap","id","SubNavFolder","defaultOpen","openProp","onToggle","uncontrolledOpen","setUncontrolledOpen","isControlled","undefined","handleToggleClick","next"],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useId, useRef, useCallback } from 'react';
3
+ import { Flex, Box, Tooltip, Typography } from '@strapi/design-system';
4
+ import { ChevronDown } from '@strapi/icons';
5
+ import { styled } from 'styled-components';
6
+
7
+ const ANIMATION_DURATION = '0.5s';
8
+ const COLLAPSE_EASING = 'cubic-bezier(0, 1, 0, 1)';
9
+ const FolderRow = styled(Flex)`
10
+ border-radius: ${({ theme })=>theme.borderRadius};
11
+
12
+ padding-right: ${({ theme })=>theme.spaces[3]};
13
+
14
+ padding-left: ${({ theme, $depth })=>`calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};
15
+
16
+ background-color: ${({ $isDropTarget, theme })=>$isDropTarget ? theme.colors.primary100 : 'transparent'};
17
+ outline: ${({ $isDropTarget, theme })=>$isDropTarget ? `1px solid ${theme.colors.primary600}` : 'none'};
18
+ outline-offset: -1px;
19
+
20
+ &:hover {
21
+ background-color: ${({ $isDropTarget, theme })=>$isDropTarget ? theme.colors.primary100 : theme.colors.neutral100};
22
+ }
23
+ `;
24
+ const ToggleButton = styled.button`
25
+ gap: ${({ theme })=>theme.spaces[2]};
26
+ align-items: center;
27
+ display: flex;
28
+ flex: 1;
29
+
30
+ padding-block: ${({ theme })=>theme.spaces[2]};
31
+ padding-inline: 0;
32
+
33
+ min-width: 0;
34
+
35
+ background: transparent;
36
+ border: none;
37
+
38
+ text-align: left;
39
+ cursor: pointer;
40
+
41
+ &:focus-visible {
42
+ outline-offset: -2px;
43
+ }
44
+ `;
45
+ const EndActionWrapper = styled(Flex)`
46
+ flex-shrink: 0;
47
+ opacity: 0;
48
+ transition: opacity 0.1s ease-out;
49
+
50
+ ${FolderRow}:hover &,
51
+ ${FolderRow}:focus-within & {
52
+ opacity: 1;
53
+ }
54
+ `;
55
+ const Collapsible = styled.div`
56
+ grid-template-rows: ${({ $open })=>$open ? '1fr' : '0fr'};
57
+ display: grid;
58
+
59
+ transition: grid-template-rows ${ANIMATION_DURATION} ${COLLAPSE_EASING};
60
+ `;
61
+ const CollapsibleInner = styled.div`
62
+ overflow: hidden;
63
+ min-height: 0;
64
+ `;
65
+ const FolderView = ({ onToggleClick, isDropTarget, endAction, children, rowRef, label, depth, open })=>{
66
+ const listId = useId();
67
+ const [isLabelTruncated, setIsLabelTruncated] = useState(false);
68
+ const resizeObserverRef = useRef(null);
69
+ // A callback ref (rather than useRef + useEffect) so measurement survives the label
70
+ // element remounting when it moves in and out of the Tooltip wrapper below.
71
+ const measureLabelRef = useCallback((node)=>{
72
+ if (resizeObserverRef.current) {
73
+ resizeObserverRef.current.disconnect();
74
+ resizeObserverRef.current = null;
75
+ }
76
+ if (!node) {
77
+ return;
78
+ }
79
+ const measure = ()=>{
80
+ setIsLabelTruncated(node.scrollWidth > node.clientWidth);
81
+ };
82
+ measure();
83
+ if (typeof ResizeObserver === 'undefined') {
84
+ return;
85
+ }
86
+ resizeObserverRef.current = new ResizeObserver(measure);
87
+ resizeObserverRef.current.observe(node);
88
+ }, []);
89
+ const applyInertWhenClosed = useCallback((node)=>{
90
+ if (!node) {
91
+ return;
92
+ }
93
+ if (open) {
94
+ node.removeAttribute('inert');
95
+ } else {
96
+ node.setAttribute('inert', '');
97
+ }
98
+ }, [
99
+ open
100
+ ]);
101
+ const labelTypography = /*#__PURE__*/ jsx(Typography, {
102
+ textColor: "neutral800",
103
+ fontWeight: "semiBold",
104
+ ref: measureLabelRef,
105
+ overflow: "hidden",
106
+ tag: "span",
107
+ style: {
108
+ flex: 1,
109
+ minWidth: 0,
110
+ textOverflow: 'ellipsis',
111
+ whiteSpace: 'nowrap'
112
+ },
113
+ children: label
114
+ });
115
+ return /*#__PURE__*/ jsxs(Box, {
116
+ children: [
117
+ /*#__PURE__*/ jsxs(FolderRow, {
118
+ ref: rowRef,
119
+ $depth: depth,
120
+ $isDropTarget: isDropTarget,
121
+ alignItems: "center",
122
+ children: [
123
+ /*#__PURE__*/ jsxs(ToggleButton, {
124
+ onClick: onToggleClick,
125
+ "aria-controls": listId,
126
+ "aria-expanded": open,
127
+ type: "button",
128
+ children: [
129
+ /*#__PURE__*/ jsx(ChevronDown, {
130
+ fill: "neutral500",
131
+ "aria-hidden": true,
132
+ style: {
133
+ transform: `rotate(${open ? '0deg' : '-90deg'})`,
134
+ transition: `transform ${ANIMATION_DURATION}`,
135
+ flexShrink: 0
136
+ }
137
+ }),
138
+ isLabelTruncated ? /*#__PURE__*/ jsx(Tooltip, {
139
+ label: label,
140
+ children: labelTypography
141
+ }) : labelTypography
142
+ ]
143
+ }),
144
+ endAction != null && /*#__PURE__*/ jsx(EndActionWrapper, {
145
+ gap: 2,
146
+ alignItems: "center",
147
+ children: endAction
148
+ })
149
+ ]
150
+ }),
151
+ /*#__PURE__*/ jsx(Collapsible, {
152
+ $open: open,
153
+ id: listId,
154
+ children: /*#__PURE__*/ jsx(CollapsibleInner, {
155
+ ref: applyInertWhenClosed,
156
+ children: children
157
+ })
158
+ })
159
+ ]
160
+ });
161
+ };
162
+ const SubNavFolder = ({ defaultOpen = false, open: openProp, isDropTarget, endAction, children, onToggle, rowRef, label, depth = 0 })=>{
163
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
164
+ const isControlled = openProp !== undefined;
165
+ const open = isControlled ? openProp : uncontrolledOpen;
166
+ const handleToggleClick = ()=>{
167
+ const next = !open;
168
+ if (!isControlled) {
169
+ setUncontrolledOpen(next);
170
+ }
171
+ onToggle?.(next);
172
+ };
173
+ return /*#__PURE__*/ jsx(FolderView, {
174
+ onToggleClick: handleToggleClick,
175
+ isDropTarget: isDropTarget,
176
+ endAction: endAction,
177
+ rowRef: rowRef,
178
+ label: label,
179
+ depth: depth,
180
+ open: open,
181
+ children: children
182
+ });
183
+ };
184
+
185
+ export { SubNavFolder };
186
+ //# sourceMappingURL=SubNavFolder.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubNavFolder.mjs","sources":["../../../../../admin/src/components/SubNavFolder.tsx"],"sourcesContent":["import { useCallback, useId, useRef, useState } from 'react';\n\nimport { Box, Flex, Tooltip, Typography } from '@strapi/design-system';\nimport { ChevronDown } from '@strapi/icons';\nimport { styled } from 'styled-components';\n\nconst ANIMATION_DURATION = '0.5s';\nconst COLLAPSE_EASING = 'cubic-bezier(0, 1, 0, 1)';\n\ninterface SubNavFolderProps {\n label: string;\n depth?: number;\n open?: boolean;\n defaultOpen?: boolean;\n onToggle?: (open: boolean) => void;\n endAction?: React.ReactNode;\n /** Ref attached to the row element used as a drag-and-drop drop target. */\n rowRef?: React.Ref<HTMLDivElement>;\n isDropTarget?: boolean;\n children?: React.ReactNode;\n}\n\nconst FolderRow = styled(Flex)<{ $depth: number; $isDropTarget?: boolean }>`\n border-radius: ${({ theme }) => theme.borderRadius};\n\n padding-right: ${({ theme }) => theme.spaces[3]};\n\n padding-left: ${({ theme, $depth }) =>\n `calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};\n\n background-color: ${({ $isDropTarget, theme }) =>\n $isDropTarget ? theme.colors.primary100 : 'transparent'};\n outline: ${({ $isDropTarget, theme }) =>\n $isDropTarget ? `1px solid ${theme.colors.primary600}` : 'none'};\n outline-offset: -1px;\n\n &:hover {\n background-color: ${({ $isDropTarget, theme }) =>\n $isDropTarget ? theme.colors.primary100 : theme.colors.neutral100};\n }\n`;\n\nconst ToggleButton = styled.button`\n gap: ${({ theme }) => theme.spaces[2]};\n align-items: center;\n display: flex;\n flex: 1;\n\n padding-block: ${({ theme }) => theme.spaces[2]};\n padding-inline: 0;\n\n min-width: 0;\n\n background: transparent;\n border: none;\n\n text-align: left;\n cursor: pointer;\n\n &:focus-visible {\n outline-offset: -2px;\n }\n`;\n\nconst EndActionWrapper = styled(Flex)`\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 0.1s ease-out;\n\n ${FolderRow}:hover &,\n ${FolderRow}:focus-within & {\n opacity: 1;\n }\n`;\n\nconst Collapsible = styled.div<{ $open: boolean }>`\n grid-template-rows: ${({ $open }) => ($open ? '1fr' : '0fr')};\n display: grid;\n\n transition: grid-template-rows ${ANIMATION_DURATION} ${COLLAPSE_EASING};\n`;\n\nconst CollapsibleInner = styled.div`\n overflow: hidden;\n min-height: 0;\n`;\n\ninterface FolderViewProps {\n rowRef?: React.Ref<HTMLDivElement>;\n endAction?: React.ReactNode;\n children?: React.ReactNode;\n onToggleClick: () => void;\n isDropTarget?: boolean;\n label: string;\n depth: number;\n open: boolean;\n}\n\nconst FolderView = ({\n onToggleClick,\n isDropTarget,\n endAction,\n children,\n rowRef,\n label,\n depth,\n open,\n}: FolderViewProps) => {\n const listId = useId();\n\n const [isLabelTruncated, setIsLabelTruncated] = useState(false);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n\n // A callback ref (rather than useRef + useEffect) so measurement survives the label\n // element remounting when it moves in and out of the Tooltip wrapper below.\n const measureLabelRef = useCallback((node: HTMLElement | null) => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n resizeObserverRef.current = null;\n }\n\n if (!node) {\n return;\n }\n\n const measure = () => {\n setIsLabelTruncated(node.scrollWidth > node.clientWidth);\n };\n\n measure();\n\n if (typeof ResizeObserver === 'undefined') {\n return;\n }\n\n resizeObserverRef.current = new ResizeObserver(measure);\n resizeObserverRef.current.observe(node);\n }, []);\n\n const applyInertWhenClosed = useCallback(\n (node: HTMLDivElement | null) => {\n if (!node) {\n return;\n }\n\n if (open) {\n node.removeAttribute('inert');\n } else {\n node.setAttribute('inert', '');\n }\n },\n [open]\n );\n\n const labelTypography = (\n <Typography\n textColor=\"neutral800\"\n fontWeight=\"semiBold\"\n ref={measureLabelRef}\n overflow=\"hidden\"\n tag=\"span\"\n style={{ flex: 1, minWidth: 0, textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n >\n {label}\n </Typography>\n );\n\n return (\n <Box>\n <FolderRow ref={rowRef} $depth={depth} $isDropTarget={isDropTarget} alignItems=\"center\">\n <ToggleButton\n onClick={onToggleClick}\n aria-controls={listId}\n aria-expanded={open}\n type=\"button\"\n >\n <ChevronDown\n fill=\"neutral500\"\n aria-hidden\n style={{\n transform: `rotate(${open ? '0deg' : '-90deg'})`,\n transition: `transform ${ANIMATION_DURATION}`,\n flexShrink: 0,\n }}\n />\n {isLabelTruncated ? <Tooltip label={label}>{labelTypography}</Tooltip> : labelTypography}\n </ToggleButton>\n {endAction != null && (\n <EndActionWrapper gap={2} alignItems=\"center\">\n {endAction}\n </EndActionWrapper>\n )}\n </FolderRow>\n <Collapsible $open={open} id={listId}>\n <CollapsibleInner ref={applyInertWhenClosed}>{children}</CollapsibleInner>\n </Collapsible>\n </Box>\n );\n};\n\nconst SubNavFolder = ({\n defaultOpen = false,\n open: openProp,\n isDropTarget,\n endAction,\n children,\n onToggle,\n rowRef,\n label,\n depth = 0,\n}: SubNavFolderProps) => {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n\n const isControlled = openProp !== undefined;\n const open = isControlled ? openProp : uncontrolledOpen;\n\n const handleToggleClick = () => {\n const next = !open;\n\n if (!isControlled) {\n setUncontrolledOpen(next);\n }\n\n onToggle?.(next);\n };\n\n return (\n <FolderView\n onToggleClick={handleToggleClick}\n isDropTarget={isDropTarget}\n endAction={endAction}\n rowRef={rowRef}\n label={label}\n depth={depth}\n open={open}\n >\n {children}\n </FolderView>\n );\n};\n\nexport { SubNavFolder };\nexport type { SubNavFolderProps };\n"],"names":["ANIMATION_DURATION","COLLAPSE_EASING","FolderRow","styled","Flex","theme","borderRadius","spaces","$depth","$isDropTarget","colors","primary100","primary600","neutral100","ToggleButton","button","EndActionWrapper","Collapsible","div","$open","CollapsibleInner","FolderView","onToggleClick","isDropTarget","endAction","children","rowRef","label","depth","open","listId","useId","isLabelTruncated","setIsLabelTruncated","useState","resizeObserverRef","useRef","measureLabelRef","useCallback","node","current","disconnect","measure","scrollWidth","clientWidth","ResizeObserver","observe","applyInertWhenClosed","removeAttribute","setAttribute","labelTypography","_jsx","Typography","textColor","fontWeight","ref","overflow","tag","style","flex","minWidth","textOverflow","whiteSpace","_jsxs","Box","alignItems","onClick","aria-controls","aria-expanded","type","ChevronDown","fill","aria-hidden","transform","transition","flexShrink","Tooltip","gap","id","SubNavFolder","defaultOpen","openProp","onToggle","uncontrolledOpen","setUncontrolledOpen","isControlled","undefined","handleToggleClick","next"],"mappings":"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"}
@@ -9,105 +9,75 @@ var dateFns = require('date-fns');
9
9
  var reactIntl = require('react-intl');
10
10
  var styledComponents = require('styled-components');
11
11
  var admin = require('../services/admin.js');
12
- var theme = require('../constants/theme.js');
13
12
  var usePersistentState = require('../hooks/usePersistentState.js');
13
+ var DismissibleBanner = require('./DismissibleBanner.js');
14
14
 
15
- const BannerBackground = styledComponents.styled(designSystem.Flex)`
16
- background: linear-gradient(
17
- 90deg,
18
- ${({ theme })=>theme.colors.primary600} 0%,
19
- ${({ theme })=>theme.colors.alternative600} 121.48%
20
- );
21
- position: relative;
22
- `;
23
- const FixedButtonWrapper = styledComponents.styled(designSystem.Box)`
15
+ /**
16
+ * Unlike `DismissibleBanner`'s own close button, this has no banner box left to
17
+ * anchor to once dismissed (the banner unmounts entirely), so it stays pinned
18
+ * to the viewport instead.
19
+ */ const FixedButtonWrapper = styledComponents.styled(designSystem.Box)`
24
20
  position: fixed;
25
21
  display: flex;
26
22
  flex-direction: column;
27
- z-index: 11;
23
+ z-index: 1;
28
24
  align-items: flex-end;
29
25
  top: 9px;
30
26
  right: 16px;
31
27
  `;
32
28
  const Banner = ({ isTrialEndedRecently, onDismiss })=>{
33
29
  const { formatMessage } = reactIntl.useIntl();
34
- return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
35
- children: [
36
- /*#__PURE__*/ jsxRuntime.jsx(BannerBackground, {
37
- width: "100%",
38
- justifyContent: "center",
39
- children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
40
- justifyContent: "center",
41
- alignItems: "center",
42
- width: "100%",
43
- paddingTop: 2,
44
- paddingBottom: 2,
45
- paddingLeft: theme.RESPONSIVE_DEFAULT_SPACING,
46
- paddingRight: theme.RESPONSIVE_DEFAULT_SPACING,
47
- gap: 2,
48
- children: [
49
- /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
50
- children: [
51
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
52
- variant: "delta",
53
- fontWeight: "bold",
54
- textColor: "neutral0",
55
- textAlign: "center",
56
- fontSize: 2,
57
- children: formatMessage(isTrialEndedRecently ? {
58
- id: 'app.components.UpsellBanner.intro.ended',
59
- defaultMessage: 'Your trial has ended: '
60
- } : {
61
- id: 'app.components.UpsellBanner.intro',
62
- defaultMessage: 'Access to Growth plan features: '
63
- })
64
- }),
65
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
66
- variant: "delta",
67
- textColor: "neutral0",
68
- textAlign: "center",
69
- paddingRight: 4,
70
- fontSize: 2,
71
- children: formatMessage(isTrialEndedRecently ? {
72
- id: 'app.components.UpsellBanner.text.ended',
73
- defaultMessage: 'Keep access to Growth features by upgrading now.'
74
- } : {
75
- id: 'app.components.UpsellBanner.text',
76
- defaultMessage: 'As part of your trial, you can explore premium tools such as Content History, Releases, and Single Sign-On (SSO).'
77
- })
78
- })
79
- ]
80
- }),
81
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
82
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
83
- width: "max-content",
84
- variant: "tertiary",
85
- href: "https://billing.strapi.io",
86
- target: "_blank",
87
- children: formatMessage(isTrialEndedRecently ? {
88
- id: 'app.components.UpsellBanner.button.ended',
89
- defaultMessage: 'Keep Growth plan'
90
- } : {
91
- id: 'app.components.UpsellBanner.button',
92
- defaultMessage: 'Upgrade now'
93
- })
94
- })
95
- })
96
- ]
97
- })
98
- }),
99
- /*#__PURE__*/ jsxRuntime.jsx(FixedButtonWrapper, {
100
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
101
- withTooltip: false,
102
- label: formatMessage({
103
- id: 'app.components.UpsellBanner.close',
104
- defaultMessage: 'Close'
105
- }),
106
- onClick: onDismiss,
107
- children: /*#__PURE__*/ jsxRuntime.jsx(icons.Cross, {})
30
+ return /*#__PURE__*/ jsxRuntime.jsx(DismissibleBanner.DismissibleBanner, {
31
+ onDismiss: onDismiss,
32
+ closeLabel: formatMessage({
33
+ id: 'app.components.UpsellBanner.close',
34
+ defaultMessage: 'Close'
35
+ }),
36
+ message: /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
37
+ children: [
38
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
39
+ variant: "delta",
40
+ fontWeight: "bold",
41
+ textColor: "neutral0",
42
+ textAlign: "center",
43
+ fontSize: 2,
44
+ children: formatMessage(isTrialEndedRecently ? {
45
+ id: 'app.components.UpsellBanner.intro.ended',
46
+ defaultMessage: 'Your trial has ended: '
47
+ } : {
48
+ id: 'app.components.UpsellBanner.intro',
49
+ defaultMessage: 'Access to Growth plan features: '
50
+ })
51
+ }),
52
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
53
+ variant: "delta",
54
+ textColor: "neutral0",
55
+ textAlign: "center",
56
+ paddingRight: 4,
57
+ fontSize: 2,
58
+ children: formatMessage(isTrialEndedRecently ? {
59
+ id: 'app.components.UpsellBanner.text.ended',
60
+ defaultMessage: 'Keep access to Growth features by upgrading now.'
61
+ } : {
62
+ id: 'app.components.UpsellBanner.text',
63
+ defaultMessage: 'As part of your trial, you can explore premium tools such as Content History, Releases, and Single Sign-On (SSO).'
64
+ })
108
65
  })
66
+ ]
67
+ }),
68
+ action: /*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
69
+ width: "max-content",
70
+ variant: "tertiary",
71
+ href: "https://billing.strapi.io",
72
+ target: "_blank",
73
+ children: formatMessage(isTrialEndedRecently ? {
74
+ id: 'app.components.UpsellBanner.button.ended',
75
+ defaultMessage: 'Keep Growth plan'
76
+ } : {
77
+ id: 'app.components.UpsellBanner.button',
78
+ defaultMessage: 'Upgrade now'
109
79
  })
110
- ]
80
+ })
111
81
  });
112
82
  };
113
83
  const UpsellBanner = ()=>{
@@ -1 +1 @@
1
- {"version":3,"file":"UpsellBanner.js","sources":["../../../../../admin/src/components/UpsellBanner.tsx"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';\nimport { Box, Flex, IconButton, LinkButton, Typography } from '@strapi/design-system';\nimport { ArrowsOut, Cross } from '@strapi/icons';\nimport { isAfter, isValid, subDays } from 'date-fns';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { useGetLicenseTrialTimeLeftQuery } from '../../src/services/admin';\nimport { RESPONSIVE_DEFAULT_SPACING } from '../constants/theme';\nimport { useScopedPersistentState } from '../hooks/usePersistentState';\n\nconst BannerBackground = styled(Flex)`\n background: linear-gradient(\n 90deg,\n ${({ theme }) => theme.colors.primary600} 0%,\n ${({ theme }) => theme.colors.alternative600} 121.48%\n );\n position: relative;\n`;\n\nconst FixedButtonWrapper = styled(Box)`\n position: fixed;\n display: flex;\n flex-direction: column;\n z-index: 11;\n align-items: flex-end;\n top: 9px;\n right: 16px;\n`;\n\nconst Banner = ({\n isTrialEndedRecently,\n onDismiss,\n}: {\n isTrialEndedRecently: boolean;\n onDismiss: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n return (\n <>\n <BannerBackground width=\"100%\" justifyContent=\"center\">\n <Flex\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n paddingTop={2}\n paddingBottom={2}\n paddingLeft={RESPONSIVE_DEFAULT_SPACING}\n paddingRight={RESPONSIVE_DEFAULT_SPACING}\n gap={2}\n >\n <Box>\n <Typography\n variant=\"delta\"\n fontWeight=\"bold\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n fontSize={2}\n >\n {formatMessage(\n isTrialEndedRecently\n ? {\n id: 'app.components.UpsellBanner.intro.ended',\n defaultMessage: 'Your trial has ended: ',\n }\n : {\n id: 'app.components.UpsellBanner.intro',\n defaultMessage: 'Access to Growth plan features: ',\n }\n )}\n </Typography>\n <Typography\n variant=\"delta\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n paddingRight={4}\n fontSize={2}\n >\n {formatMessage(\n isTrialEndedRecently\n ? {\n id: 'app.components.UpsellBanner.text.ended',\n defaultMessage: 'Keep access to Growth features by upgrading now.',\n }\n : {\n id: 'app.components.UpsellBanner.text',\n defaultMessage:\n 'As part of your trial, you can explore premium tools such as Content History, Releases, and Single Sign-On (SSO).',\n }\n )}\n </Typography>\n </Box>\n <Box>\n <LinkButton\n width=\"max-content\"\n variant=\"tertiary\"\n href=\"https://billing.strapi.io\"\n target=\"_blank\"\n >\n {formatMessage(\n isTrialEndedRecently\n ? {\n id: 'app.components.UpsellBanner.button.ended',\n defaultMessage: 'Keep Growth plan',\n }\n : {\n id: 'app.components.UpsellBanner.button',\n defaultMessage: 'Upgrade now',\n }\n )}\n </LinkButton>\n </Box>\n </Flex>\n </BannerBackground>\n <FixedButtonWrapper>\n <IconButton\n withTooltip={false}\n label={formatMessage({\n id: 'app.components.UpsellBanner.close',\n defaultMessage: 'Close',\n })}\n onClick={onDismiss}\n >\n <Cross />\n </IconButton>\n </FixedButtonWrapper>\n </>\n );\n};\n\nconst UpsellBanner = () => {\n const { license } = useLicenseLimits();\n const { formatMessage } = useIntl();\n\n const [cachedTrialEndsAt, setCachedTrialEndsAt] = useScopedPersistentState<string | undefined>(\n 'STRAPI_FREE_TRIAL_ENDS_AT',\n undefined\n );\n\n const [dismissedFor, setDismissedFor] = useScopedPersistentState<string | undefined>(\n 'STRAPI_UPSELL_BANNER_DISMISSED_FOR',\n undefined\n );\n\n const sevenDaysAgo = subDays(new Date(), 7);\n\n const timeLeftData = useGetLicenseTrialTimeLeftQuery(undefined, {\n skip: !license?.isTrial,\n });\n\n useEffect(() => {\n if (timeLeftData.data?.trialEndsAt) {\n setCachedTrialEndsAt(timeLeftData.data.trialEndsAt);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [timeLeftData.data?.trialEndsAt]);\n\n // When the license is not a trial + not EE, and the cached trial end date is found in the localstorage, that means the trial has ended\n // We show the banner to encourage the user to upgrade (for 7 days after the trial ends)\n const isTrialEndedRecently = Boolean(\n !license?.isTrial &&\n !window.strapi.isEE &&\n cachedTrialEndsAt &&\n isAfter(new Date(cachedTrialEndsAt), sevenDaysAgo)\n );\n\n const trialEndsAt = timeLeftData.data?.trialEndsAt ?? cachedTrialEndsAt;\n\n const toCanonicalISO = (v: string | undefined): string | undefined => {\n if (!v) return undefined;\n const date = new Date(v);\n return isValid(date) ? date.toISOString() : undefined;\n };\n\n const isDismissed = Boolean(\n trialEndsAt && toCanonicalISO(dismissedFor) === toCanonicalISO(trialEndsAt)\n );\n\n const handleDismiss = () => setDismissedFor(toCanonicalISO(trialEndsAt));\n const handleReopen = () => setDismissedFor(undefined);\n\n if (!(timeLeftData.data?.trialEndsAt || isTrialEndedRecently)) {\n return null;\n }\n\n if (isDismissed) {\n return (\n <FixedButtonWrapper>\n <IconButton\n withTooltip={false}\n label={formatMessage({\n id: 'app.components.UpsellBanner.reopen',\n defaultMessage: 'Reopen banner',\n })}\n onClick={handleReopen}\n >\n <ArrowsOut />\n </IconButton>\n </FixedButtonWrapper>\n );\n }\n\n return <Banner isTrialEndedRecently={isTrialEndedRecently} onDismiss={handleDismiss} />;\n};\n\nexport { UpsellBanner };\n"],"names":["BannerBackground","styled","Flex","theme","colors","primary600","alternative600","FixedButtonWrapper","Box","Banner","isTrialEndedRecently","onDismiss","formatMessage","useIntl","_jsxs","_Fragment","_jsx","width","justifyContent","alignItems","paddingTop","paddingBottom","paddingLeft","RESPONSIVE_DEFAULT_SPACING","paddingRight","gap","Typography","variant","fontWeight","textColor","textAlign","fontSize","id","defaultMessage","LinkButton","href","target","IconButton","withTooltip","label","onClick","Cross","UpsellBanner","license","useLicenseLimits","cachedTrialEndsAt","setCachedTrialEndsAt","useScopedPersistentState","undefined","dismissedFor","setDismissedFor","sevenDaysAgo","subDays","Date","timeLeftData","useGetLicenseTrialTimeLeftQuery","skip","isTrial","useEffect","data","trialEndsAt","Boolean","window","strapi","isEE","isAfter","toCanonicalISO","v","date","isValid","toISOString","isDismissed","handleDismiss","handleReopen","ArrowsOut"],"mappings":";;;;;;;;;;;;;;AAaA,MAAMA,gBAAAA,GAAmBC,uBAAAA,CAAOC,iBAAAA,CAAK;;;IAGjC,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAAA,CAAMC,MAAM,CAACC,UAAU,CAAC;IACzC,EAAE,CAAC,EAAEF,KAAK,EAAE,GAAKA,KAAAA,CAAMC,MAAM,CAACE,cAAc,CAAC;;;AAGjD,CAAC;AAED,MAAMC,kBAAAA,GAAqBN,uBAAAA,CAAOO,gBAAAA,CAAI;;;;;;;;AAQtC,CAAC;AAED,MAAMC,SAAS,CAAC,EACdC,oBAAoB,EACpBC,SAAS,EAIV,GAAA;IACC,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;IAE1B,qBACEC,eAAA,CAAAC,mBAAA,EAAA;;0BACEC,cAAA,CAAChB,gBAAAA,EAAAA;gBAAiBiB,KAAAA,EAAM,MAAA;gBAAOC,cAAAA,EAAe,QAAA;AAC5C,gBAAA,QAAA,gBAAAJ,eAAA,CAACZ,iBAAAA,EAAAA;oBACCgB,cAAAA,EAAe,QAAA;oBACfC,UAAAA,EAAW,QAAA;oBACXF,KAAAA,EAAM,MAAA;oBACNG,UAAAA,EAAY,CAAA;oBACZC,aAAAA,EAAe,CAAA;oBACfC,WAAAA,EAAaC,gCAAAA;oBACbC,YAAAA,EAAcD,gCAAAA;oBACdE,GAAAA,EAAK,CAAA;;sCAELX,eAAA,CAACN,gBAAAA,EAAAA;;8CACCQ,cAAA,CAACU,uBAAAA,EAAAA;oCACCC,OAAAA,EAAQ,OAAA;oCACRC,UAAAA,EAAW,MAAA;oCACXC,SAAAA,EAAU,UAAA;oCACVC,SAAAA,EAAU,QAAA;oCACVC,QAAAA,EAAU,CAAA;AAETnB,oCAAAA,QAAAA,EAAAA,aAAAA,CACCF,oBAAAA,GACI;wCACEsB,EAAAA,EAAI,yCAAA;wCACJC,cAAAA,EAAgB;qCAClB,GACA;wCACED,EAAAA,EAAI,mCAAA;wCACJC,cAAAA,EAAgB;AAClB,qCAAA;;8CAGRjB,cAAA,CAACU,uBAAAA,EAAAA;oCACCC,OAAAA,EAAQ,OAAA;oCACRE,SAAAA,EAAU,UAAA;oCACVC,SAAAA,EAAU,QAAA;oCACVN,YAAAA,EAAc,CAAA;oCACdO,QAAAA,EAAU,CAAA;AAETnB,oCAAAA,QAAAA,EAAAA,aAAAA,CACCF,oBAAAA,GACI;wCACEsB,EAAAA,EAAI,wCAAA;wCACJC,cAAAA,EAAgB;qCAClB,GACA;wCACED,EAAAA,EAAI,kCAAA;wCACJC,cAAAA,EACE;AACJ,qCAAA;;;;sCAIVjB,cAAA,CAACR,gBAAAA,EAAAA;AACC,4BAAA,QAAA,gBAAAQ,cAAA,CAACkB,uBAAAA,EAAAA;gCACCjB,KAAAA,EAAM,aAAA;gCACNU,OAAAA,EAAQ,UAAA;gCACRQ,IAAAA,EAAK,2BAAA;gCACLC,MAAAA,EAAO,QAAA;AAENxB,gCAAAA,QAAAA,EAAAA,aAAAA,CACCF,oBAAAA,GACI;oCACEsB,EAAAA,EAAI,0CAAA;oCACJC,cAAAA,EAAgB;iCAClB,GACA;oCACED,EAAAA,EAAI,oCAAA;oCACJC,cAAAA,EAAgB;AAClB,iCAAA;;;;;;0BAMdjB,cAAA,CAACT,kBAAAA,EAAAA;AACC,gBAAA,QAAA,gBAAAS,cAAA,CAACqB,uBAAAA,EAAAA;oBACCC,WAAAA,EAAa,KAAA;AACbC,oBAAAA,KAAAA,EAAO3B,aAAAA,CAAc;wBACnBoB,EAAAA,EAAI,mCAAA;wBACJC,cAAAA,EAAgB;AAClB,qBAAA,CAAA;oBACAO,OAAAA,EAAS7B,SAAAA;AAET,oBAAA,QAAA,gBAAAK,cAAA,CAACyB,WAAAA,EAAAA,EAAAA;;;;;AAKX,CAAA;AAEA,MAAMC,YAAAA,GAAe,IAAA;IACnB,MAAM,EAAEC,OAAO,EAAE,GAAGC,mBAAAA,EAAAA;IACpB,MAAM,EAAEhC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAE1B,IAAA,MAAM,CAACgC,iBAAAA,EAAmBC,oBAAAA,CAAqB,GAAGC,4CAChD,2BAAA,EACAC,SAAAA,CAAAA;AAGF,IAAA,MAAM,CAACC,YAAAA,EAAcC,eAAAA,CAAgB,GAAGH,4CACtC,oCAAA,EACAC,SAAAA,CAAAA;IAGF,MAAMG,YAAAA,GAAeC,eAAAA,CAAQ,IAAIC,IAAAA,EAAAA,EAAQ,CAAA,CAAA;IAEzC,MAAMC,YAAAA,GAAeC,sCAAgCP,SAAAA,EAAW;AAC9DQ,QAAAA,IAAAA,EAAM,CAACb,OAAAA,EAASc;AAClB,KAAA,CAAA;IAEAC,eAAAA,CAAU,IAAA;QACR,IAAIJ,YAAAA,CAAaK,IAAI,EAAEC,WAAAA,EAAa;YAClCd,oBAAAA,CAAqBQ,YAAAA,CAAaK,IAAI,CAACC,WAAW,CAAA;AACpD,QAAA;;IAEF,CAAA,EAAG;AAACN,QAAAA,YAAAA,CAAaK,IAAI,EAAEC;AAAY,KAAA,CAAA;;;AAInC,IAAA,MAAMlD,oBAAAA,GAAuBmD,OAAAA,CAC3B,CAAClB,OAAAA,EAASc,WACR,CAACK,MAAAA,CAAOC,MAAM,CAACC,IAAI,IACnBnB,iBAAAA,IACAoB,eAAAA,CAAQ,IAAIZ,KAAKR,iBAAAA,CAAAA,EAAoBM,YAAAA,CAAAA,CAAAA;AAGzC,IAAA,MAAMS,WAAAA,GAAcN,YAAAA,CAAaK,IAAI,EAAEC,WAAAA,IAAef,iBAAAA;AAEtD,IAAA,MAAMqB,iBAAiB,CAACC,CAAAA,GAAAA;QACtB,IAAI,CAACA,GAAG,OAAOnB,SAAAA;QACf,MAAMoB,IAAAA,GAAO,IAAIf,IAAAA,CAAKc,CAAAA,CAAAA;AACtB,QAAA,OAAOE,eAAAA,CAAQD,IAAAA,CAAAA,GAAQA,IAAAA,CAAKE,WAAW,EAAA,GAAKtB,SAAAA;AAC9C,IAAA,CAAA;AAEA,IAAA,MAAMuB,WAAAA,GAAcV,OAAAA,CAClBD,WAAAA,IAAeM,cAAAA,CAAejB,kBAAkBiB,cAAAA,CAAeN,WAAAA,CAAAA,CAAAA;IAGjE,MAAMY,aAAAA,GAAgB,IAAMtB,eAAAA,CAAgBgB,cAAAA,CAAeN,WAAAA,CAAAA,CAAAA;IAC3D,MAAMa,YAAAA,GAAe,IAAMvB,eAAAA,CAAgBF,SAAAA,CAAAA;AAE3C,IAAA,IAAI,EAAEM,YAAAA,CAAaK,IAAI,EAAEC,WAAAA,IAAelD,oBAAmB,CAAA,EAAI;QAC7D,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,IAAI6D,WAAAA,EAAa;AACf,QAAA,qBACEvD,cAAA,CAACT,kBAAAA,EAAAA;AACC,YAAA,QAAA,gBAAAS,cAAA,CAACqB,uBAAAA,EAAAA;gBACCC,WAAAA,EAAa,KAAA;AACbC,gBAAAA,KAAAA,EAAO3B,aAAAA,CAAc;oBACnBoB,EAAAA,EAAI,oCAAA;oBACJC,cAAAA,EAAgB;AAClB,iBAAA,CAAA;gBACAO,OAAAA,EAASiC,YAAAA;AAET,gBAAA,QAAA,gBAAAzD,cAAA,CAAC0D,eAAAA,EAAAA,EAAAA;;;AAIT,IAAA;AAEA,IAAA,qBAAO1D,cAAA,CAACP,MAAAA,EAAAA;QAAOC,oBAAAA,EAAsBA,oBAAAA;QAAsBC,SAAAA,EAAW6D;;AACxE;;;;"}
1
+ {"version":3,"file":"UpsellBanner.js","sources":["../../../../../admin/src/components/UpsellBanner.tsx"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';\nimport { Box, IconButton, LinkButton, Typography } from '@strapi/design-system';\nimport { ArrowsOut } from '@strapi/icons';\nimport { isAfter, isValid, subDays } from 'date-fns';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { useGetLicenseTrialTimeLeftQuery } from '../../src/services/admin';\nimport { useScopedPersistentState } from '../hooks/usePersistentState';\n\nimport { DismissibleBanner } from './DismissibleBanner';\n\n/**\n * Unlike `DismissibleBanner`'s own close button, this has no banner box left to\n * anchor to once dismissed (the banner unmounts entirely), so it stays pinned\n * to the viewport instead.\n */\nconst FixedButtonWrapper = styled(Box)`\n position: fixed;\n display: flex;\n flex-direction: column;\n z-index: 1;\n align-items: flex-end;\n top: 9px;\n right: 16px;\n`;\n\nconst Banner = ({\n isTrialEndedRecently,\n onDismiss,\n}: {\n isTrialEndedRecently: boolean;\n onDismiss: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n return (\n <DismissibleBanner\n onDismiss={onDismiss}\n closeLabel={formatMessage({\n id: 'app.components.UpsellBanner.close',\n defaultMessage: 'Close',\n })}\n message={\n <>\n <Typography\n variant=\"delta\"\n fontWeight=\"bold\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n fontSize={2}\n >\n {formatMessage(\n isTrialEndedRecently\n ? {\n id: 'app.components.UpsellBanner.intro.ended',\n defaultMessage: 'Your trial has ended: ',\n }\n : {\n id: 'app.components.UpsellBanner.intro',\n defaultMessage: 'Access to Growth plan features: ',\n }\n )}\n </Typography>\n <Typography\n variant=\"delta\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n paddingRight={4}\n fontSize={2}\n >\n {formatMessage(\n isTrialEndedRecently\n ? {\n id: 'app.components.UpsellBanner.text.ended',\n defaultMessage: 'Keep access to Growth features by upgrading now.',\n }\n : {\n id: 'app.components.UpsellBanner.text',\n defaultMessage:\n 'As part of your trial, you can explore premium tools such as Content History, Releases, and Single Sign-On (SSO).',\n }\n )}\n </Typography>\n </>\n }\n action={\n <LinkButton\n width=\"max-content\"\n variant=\"tertiary\"\n href=\"https://billing.strapi.io\"\n target=\"_blank\"\n >\n {formatMessage(\n isTrialEndedRecently\n ? {\n id: 'app.components.UpsellBanner.button.ended',\n defaultMessage: 'Keep Growth plan',\n }\n : {\n id: 'app.components.UpsellBanner.button',\n defaultMessage: 'Upgrade now',\n }\n )}\n </LinkButton>\n }\n />\n );\n};\n\nconst UpsellBanner = () => {\n const { license } = useLicenseLimits();\n const { formatMessage } = useIntl();\n\n const [cachedTrialEndsAt, setCachedTrialEndsAt] = useScopedPersistentState<string | undefined>(\n 'STRAPI_FREE_TRIAL_ENDS_AT',\n undefined\n );\n\n const [dismissedFor, setDismissedFor] = useScopedPersistentState<string | undefined>(\n 'STRAPI_UPSELL_BANNER_DISMISSED_FOR',\n undefined\n );\n\n const sevenDaysAgo = subDays(new Date(), 7);\n\n const timeLeftData = useGetLicenseTrialTimeLeftQuery(undefined, {\n skip: !license?.isTrial,\n });\n\n useEffect(() => {\n if (timeLeftData.data?.trialEndsAt) {\n setCachedTrialEndsAt(timeLeftData.data.trialEndsAt);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [timeLeftData.data?.trialEndsAt]);\n\n // When the license is not a trial + not EE, and the cached trial end date is found in the localstorage, that means the trial has ended\n // We show the banner to encourage the user to upgrade (for 7 days after the trial ends)\n const isTrialEndedRecently = Boolean(\n !license?.isTrial &&\n !window.strapi.isEE &&\n cachedTrialEndsAt &&\n isAfter(new Date(cachedTrialEndsAt), sevenDaysAgo)\n );\n\n const trialEndsAt = timeLeftData.data?.trialEndsAt ?? cachedTrialEndsAt;\n\n const toCanonicalISO = (v: string | undefined): string | undefined => {\n if (!v) return undefined;\n const date = new Date(v);\n return isValid(date) ? date.toISOString() : undefined;\n };\n\n const isDismissed = Boolean(\n trialEndsAt && toCanonicalISO(dismissedFor) === toCanonicalISO(trialEndsAt)\n );\n\n const handleDismiss = () => setDismissedFor(toCanonicalISO(trialEndsAt));\n const handleReopen = () => setDismissedFor(undefined);\n\n if (!(timeLeftData.data?.trialEndsAt || isTrialEndedRecently)) {\n return null;\n }\n\n if (isDismissed) {\n return (\n <FixedButtonWrapper>\n <IconButton\n withTooltip={false}\n label={formatMessage({\n id: 'app.components.UpsellBanner.reopen',\n defaultMessage: 'Reopen banner',\n })}\n onClick={handleReopen}\n >\n <ArrowsOut />\n </IconButton>\n </FixedButtonWrapper>\n );\n }\n\n return <Banner isTrialEndedRecently={isTrialEndedRecently} onDismiss={handleDismiss} />;\n};\n\nexport { UpsellBanner };\n"],"names":["FixedButtonWrapper","styled","Box","Banner","isTrialEndedRecently","onDismiss","formatMessage","useIntl","_jsx","DismissibleBanner","closeLabel","id","defaultMessage","message","_jsxs","_Fragment","Typography","variant","fontWeight","textColor","textAlign","fontSize","paddingRight","action","LinkButton","width","href","target","UpsellBanner","license","useLicenseLimits","cachedTrialEndsAt","setCachedTrialEndsAt","useScopedPersistentState","undefined","dismissedFor","setDismissedFor","sevenDaysAgo","subDays","Date","timeLeftData","useGetLicenseTrialTimeLeftQuery","skip","isTrial","useEffect","data","trialEndsAt","Boolean","window","strapi","isEE","isAfter","toCanonicalISO","v","date","isValid","toISOString","isDismissed","handleDismiss","handleReopen","IconButton","withTooltip","label","onClick","ArrowsOut"],"mappings":"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"}
@@ -1,111 +1,81 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { useEffect } from 'react';
3
3
  import { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';
4
- import { IconButton, Box, Flex, Typography, LinkButton } from '@strapi/design-system';
5
- import { ArrowsOut, Cross } from '@strapi/icons';
4
+ import { IconButton, Box, LinkButton, Typography } from '@strapi/design-system';
5
+ import { ArrowsOut } from '@strapi/icons';
6
6
  import { subDays, isAfter, isValid } from 'date-fns';
7
7
  import { useIntl } from 'react-intl';
8
8
  import { styled } from 'styled-components';
9
9
  import { useGetLicenseTrialTimeLeftQuery } from '../services/admin.mjs';
10
- import { RESPONSIVE_DEFAULT_SPACING } from '../constants/theme.mjs';
11
10
  import { useScopedPersistentState } from '../hooks/usePersistentState.mjs';
11
+ import { DismissibleBanner } from './DismissibleBanner.mjs';
12
12
 
13
- const BannerBackground = styled(Flex)`
14
- background: linear-gradient(
15
- 90deg,
16
- ${({ theme })=>theme.colors.primary600} 0%,
17
- ${({ theme })=>theme.colors.alternative600} 121.48%
18
- );
19
- position: relative;
20
- `;
21
- const FixedButtonWrapper = styled(Box)`
13
+ /**
14
+ * Unlike `DismissibleBanner`'s own close button, this has no banner box left to
15
+ * anchor to once dismissed (the banner unmounts entirely), so it stays pinned
16
+ * to the viewport instead.
17
+ */ const FixedButtonWrapper = styled(Box)`
22
18
  position: fixed;
23
19
  display: flex;
24
20
  flex-direction: column;
25
- z-index: 11;
21
+ z-index: 1;
26
22
  align-items: flex-end;
27
23
  top: 9px;
28
24
  right: 16px;
29
25
  `;
30
26
  const Banner = ({ isTrialEndedRecently, onDismiss })=>{
31
27
  const { formatMessage } = useIntl();
32
- return /*#__PURE__*/ jsxs(Fragment, {
33
- children: [
34
- /*#__PURE__*/ jsx(BannerBackground, {
35
- width: "100%",
36
- justifyContent: "center",
37
- children: /*#__PURE__*/ jsxs(Flex, {
38
- justifyContent: "center",
39
- alignItems: "center",
40
- width: "100%",
41
- paddingTop: 2,
42
- paddingBottom: 2,
43
- paddingLeft: RESPONSIVE_DEFAULT_SPACING,
44
- paddingRight: RESPONSIVE_DEFAULT_SPACING,
45
- gap: 2,
46
- children: [
47
- /*#__PURE__*/ jsxs(Box, {
48
- children: [
49
- /*#__PURE__*/ jsx(Typography, {
50
- variant: "delta",
51
- fontWeight: "bold",
52
- textColor: "neutral0",
53
- textAlign: "center",
54
- fontSize: 2,
55
- children: formatMessage(isTrialEndedRecently ? {
56
- id: 'app.components.UpsellBanner.intro.ended',
57
- defaultMessage: 'Your trial has ended: '
58
- } : {
59
- id: 'app.components.UpsellBanner.intro',
60
- defaultMessage: 'Access to Growth plan features: '
61
- })
62
- }),
63
- /*#__PURE__*/ jsx(Typography, {
64
- variant: "delta",
65
- textColor: "neutral0",
66
- textAlign: "center",
67
- paddingRight: 4,
68
- fontSize: 2,
69
- children: formatMessage(isTrialEndedRecently ? {
70
- id: 'app.components.UpsellBanner.text.ended',
71
- defaultMessage: 'Keep access to Growth features by upgrading now.'
72
- } : {
73
- id: 'app.components.UpsellBanner.text',
74
- defaultMessage: 'As part of your trial, you can explore premium tools such as Content History, Releases, and Single Sign-On (SSO).'
75
- })
76
- })
77
- ]
78
- }),
79
- /*#__PURE__*/ jsx(Box, {
80
- children: /*#__PURE__*/ jsx(LinkButton, {
81
- width: "max-content",
82
- variant: "tertiary",
83
- href: "https://billing.strapi.io",
84
- target: "_blank",
85
- children: formatMessage(isTrialEndedRecently ? {
86
- id: 'app.components.UpsellBanner.button.ended',
87
- defaultMessage: 'Keep Growth plan'
88
- } : {
89
- id: 'app.components.UpsellBanner.button',
90
- defaultMessage: 'Upgrade now'
91
- })
92
- })
93
- })
94
- ]
95
- })
96
- }),
97
- /*#__PURE__*/ jsx(FixedButtonWrapper, {
98
- children: /*#__PURE__*/ jsx(IconButton, {
99
- withTooltip: false,
100
- label: formatMessage({
101
- id: 'app.components.UpsellBanner.close',
102
- defaultMessage: 'Close'
103
- }),
104
- onClick: onDismiss,
105
- children: /*#__PURE__*/ jsx(Cross, {})
28
+ return /*#__PURE__*/ jsx(DismissibleBanner, {
29
+ onDismiss: onDismiss,
30
+ closeLabel: formatMessage({
31
+ id: 'app.components.UpsellBanner.close',
32
+ defaultMessage: 'Close'
33
+ }),
34
+ message: /*#__PURE__*/ jsxs(Fragment, {
35
+ children: [
36
+ /*#__PURE__*/ jsx(Typography, {
37
+ variant: "delta",
38
+ fontWeight: "bold",
39
+ textColor: "neutral0",
40
+ textAlign: "center",
41
+ fontSize: 2,
42
+ children: formatMessage(isTrialEndedRecently ? {
43
+ id: 'app.components.UpsellBanner.intro.ended',
44
+ defaultMessage: 'Your trial has ended: '
45
+ } : {
46
+ id: 'app.components.UpsellBanner.intro',
47
+ defaultMessage: 'Access to Growth plan features: '
48
+ })
49
+ }),
50
+ /*#__PURE__*/ jsx(Typography, {
51
+ variant: "delta",
52
+ textColor: "neutral0",
53
+ textAlign: "center",
54
+ paddingRight: 4,
55
+ fontSize: 2,
56
+ children: formatMessage(isTrialEndedRecently ? {
57
+ id: 'app.components.UpsellBanner.text.ended',
58
+ defaultMessage: 'Keep access to Growth features by upgrading now.'
59
+ } : {
60
+ id: 'app.components.UpsellBanner.text',
61
+ defaultMessage: 'As part of your trial, you can explore premium tools such as Content History, Releases, and Single Sign-On (SSO).'
62
+ })
106
63
  })
64
+ ]
65
+ }),
66
+ action: /*#__PURE__*/ jsx(LinkButton, {
67
+ width: "max-content",
68
+ variant: "tertiary",
69
+ href: "https://billing.strapi.io",
70
+ target: "_blank",
71
+ children: formatMessage(isTrialEndedRecently ? {
72
+ id: 'app.components.UpsellBanner.button.ended',
73
+ defaultMessage: 'Keep Growth plan'
74
+ } : {
75
+ id: 'app.components.UpsellBanner.button',
76
+ defaultMessage: 'Upgrade now'
107
77
  })
108
- ]
78
+ })
109
79
  });
110
80
  };
111
81
  const UpsellBanner = ()=>{