@devxcrew/react-ui 0.0.0-stage → 0.1.7

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 (326) hide show
  1. package/README.md +85 -2
  2. package/package.json +105 -4
  3. package/src/blocks/agent-chat-workspace/agent-chat-workspace.tsx +162 -0
  4. package/src/blocks/agent-chat-workspace/index.ts +2 -0
  5. package/src/blocks/agent-provider-settings/agent-provider-settings.tsx +183 -0
  6. package/src/blocks/agent-provider-settings/index.ts +2 -0
  7. package/src/blocks/agent-task-workspace/agent-task-workspace.tsx +48 -0
  8. package/src/blocks/agent-task-workspace/index.ts +2 -0
  9. package/src/blocks/analysis-context/analysis-context.tsx +6 -0
  10. package/src/blocks/analysis-context/index.ts +1 -0
  11. package/src/blocks/app-header/app-header.tsx +159 -0
  12. package/src/blocks/app-header/index.ts +2 -0
  13. package/src/blocks/archived-chat-workspace/archived-chat-workspace.tsx +29 -0
  14. package/src/blocks/archived-chat-workspace/index.ts +2 -0
  15. package/src/blocks/auth/README.md +32 -0
  16. package/src/blocks/auth/admin-login-page.tsx +15 -0
  17. package/src/blocks/auth/admin-password-forgot-page.tsx +5 -0
  18. package/src/blocks/auth/auth-page-layout.tsx +90 -0
  19. package/src/blocks/auth/client-login-page.tsx +20 -0
  20. package/src/blocks/auth/client-password-forgot-page.tsx +5 -0
  21. package/src/blocks/auth/identity-management-desk.tsx +530 -0
  22. package/src/blocks/auth/index.ts +12 -0
  23. package/src/blocks/auth/login-page.tsx +206 -0
  24. package/src/blocks/auth/password-forgot-page.tsx +60 -0
  25. package/src/blocks/auth/portal-pages.tsx +32 -0
  26. package/src/blocks/auth/privileged-desk.tsx +55 -0
  27. package/src/blocks/auth/register-page.tsx +117 -0
  28. package/src/blocks/auth/session-boundary.tsx +296 -0
  29. package/src/blocks/auth/super-admin-login-page.tsx +15 -0
  30. package/src/blocks/auth/super-admin-password-forgot-page.tsx +5 -0
  31. package/src/blocks/blog/blog-card.tsx +156 -0
  32. package/src/blocks/blog/blog-reader.tsx +175 -0
  33. package/src/blocks/blog/blog-types.ts +47 -0
  34. package/src/blocks/blog/index.ts +3 -0
  35. package/src/blocks/chat-composer/chat-composer.tsx +140 -0
  36. package/src/blocks/chat-composer/index.ts +1 -0
  37. package/src/blocks/chat-history/chat-history.tsx +59 -0
  38. package/src/blocks/chat-history/index.ts +1 -0
  39. package/src/blocks/chat-response-progress/chat-response-progress.tsx +34 -0
  40. package/src/blocks/chat-response-progress/index.ts +2 -0
  41. package/src/blocks/chat-runtime-controls/chat-runtime-controls.tsx +56 -0
  42. package/src/blocks/chat-runtime-controls/index.ts +2 -0
  43. package/src/blocks/chat-runtime-trace/chat-runtime-trace.tsx +71 -0
  44. package/src/blocks/chat-runtime-trace/index.ts +2 -0
  45. package/src/blocks/codex-connection-settings/codex-connection-settings.tsx +42 -0
  46. package/src/blocks/codex-connection-settings/index.ts +1 -0
  47. package/src/blocks/dropzone/dropzone-file-item.tsx +113 -0
  48. package/src/blocks/dropzone/dropzone-types.ts +32 -0
  49. package/src/blocks/dropzone/dropzone.tsx +216 -0
  50. package/src/blocks/dropzone/index.ts +3 -0
  51. package/src/blocks/ecommerce/cart/cart-drawer.tsx +228 -0
  52. package/src/blocks/ecommerce/cart/cart-types.ts +27 -0
  53. package/src/blocks/ecommerce/cart/index.ts +2 -0
  54. package/src/blocks/ecommerce/categories/categories-types.ts +23 -0
  55. package/src/blocks/ecommerce/categories/category-showcase.tsx +125 -0
  56. package/src/blocks/ecommerce/categories/index.ts +2 -0
  57. package/src/blocks/ecommerce/checkout/checkout-types.ts +48 -0
  58. package/src/blocks/ecommerce/checkout/checkout-wizard.tsx +468 -0
  59. package/src/blocks/ecommerce/checkout/index.ts +2 -0
  60. package/src/blocks/ecommerce/comparison/comparison-types.ts +28 -0
  61. package/src/blocks/ecommerce/comparison/index.ts +2 -0
  62. package/src/blocks/ecommerce/comparison/product-comparison.tsx +174 -0
  63. package/src/blocks/ecommerce/coupon-wallet/coupon-wallet-types.ts +21 -0
  64. package/src/blocks/ecommerce/coupon-wallet/coupon-wallet.tsx +154 -0
  65. package/src/blocks/ecommerce/coupon-wallet/index.ts +2 -0
  66. package/src/blocks/ecommerce/delivery-tracker/delivery-tracker-types.ts +20 -0
  67. package/src/blocks/ecommerce/delivery-tracker/delivery-tracker.tsx +169 -0
  68. package/src/blocks/ecommerce/delivery-tracker/index.ts +2 -0
  69. package/src/blocks/ecommerce/index.ts +12 -0
  70. package/src/blocks/ecommerce/payment-methods/index.ts +2 -0
  71. package/src/blocks/ecommerce/payment-methods/payment-method-selector.tsx +224 -0
  72. package/src/blocks/ecommerce/payment-methods/payment-methods-types.ts +21 -0
  73. package/src/blocks/ecommerce/price-history/index.ts +2 -0
  74. package/src/blocks/ecommerce/price-history/price-history-chart.tsx +217 -0
  75. package/src/blocks/ecommerce/price-history/price-history-types.ts +16 -0
  76. package/src/blocks/ecommerce/reviews/index.ts +2 -0
  77. package/src/blocks/ecommerce/reviews/reviews-section.tsx +309 -0
  78. package/src/blocks/ecommerce/reviews/reviews-types.ts +26 -0
  79. package/src/blocks/ecommerce/wishlist/index.ts +2 -0
  80. package/src/blocks/ecommerce/wishlist/wishlist-grid.tsx +149 -0
  81. package/src/blocks/ecommerce/wishlist/wishlist-types.ts +19 -0
  82. package/src/blocks/execution-status/README.md +25 -0
  83. package/src/blocks/execution-status/execution-status.tsx +135 -0
  84. package/src/blocks/execution-status/index.ts +2 -0
  85. package/src/blocks/file-tree/file-icons.tsx +84 -0
  86. package/src/blocks/file-tree/file-tree-node.tsx +158 -0
  87. package/src/blocks/file-tree/file-tree-types.ts +33 -0
  88. package/src/blocks/file-tree/file-tree.tsx +163 -0
  89. package/src/blocks/file-tree/index.ts +5 -0
  90. package/src/blocks/filter-builder/filter-builder.tsx +169 -0
  91. package/src/blocks/filter-builder/filter-row.tsx +164 -0
  92. package/src/blocks/filter-builder/filter-types.ts +61 -0
  93. package/src/blocks/filter-builder/index.ts +12 -0
  94. package/src/blocks/footer/footer-types.ts +35 -0
  95. package/src/blocks/footer/index.ts +2 -0
  96. package/src/blocks/footer/site-footer.tsx +212 -0
  97. package/src/blocks/form/form-block.tsx +113 -0
  98. package/src/blocks/form/form-lookup-field.tsx +60 -0
  99. package/src/blocks/form/index.ts +4 -0
  100. package/src/blocks/handover-stack/handover-stack.tsx +41 -0
  101. package/src/blocks/handover-stack/index.ts +1 -0
  102. package/src/blocks/idea-handover/idea-handover-readiness.ts +41 -0
  103. package/src/blocks/idea-handover/idea-handover-workspace.tsx +150 -0
  104. package/src/blocks/idea-handover/index.ts +4 -0
  105. package/src/blocks/kanban/index.ts +11 -0
  106. package/src/blocks/kanban/kanban-board.tsx +146 -0
  107. package/src/blocks/kanban/kanban-card.tsx +149 -0
  108. package/src/blocks/kanban/kanban-column.tsx +102 -0
  109. package/src/blocks/kanban/kanban-types.ts +38 -0
  110. package/src/blocks/loader/global-loader.tsx +90 -0
  111. package/src/blocks/loader/index.ts +1 -0
  112. package/src/blocks/mascot/README.md +21 -0
  113. package/src/blocks/mascot/index.ts +2 -0
  114. package/src/blocks/mascot/mascot.tsx +202 -0
  115. package/src/blocks/master-list/README.md +21 -0
  116. package/src/blocks/master-list/index.ts +12 -0
  117. package/src/blocks/master-list/master-form.tsx +157 -0
  118. package/src/blocks/master-list/master-list-desk.tsx +370 -0
  119. package/src/blocks/master-list/master-list.tsx +189 -0
  120. package/src/blocks/master-list/types.ts +18 -0
  121. package/src/blocks/mermaid-preview/index.ts +1 -0
  122. package/src/blocks/mermaid-preview/mermaid-preview.tsx +164 -0
  123. package/src/blocks/notifications/README.md +7 -0
  124. package/src/blocks/notifications/index.ts +1 -0
  125. package/src/blocks/notifications/notification-center-page.tsx +73 -0
  126. package/src/blocks/pricing/index.ts +7 -0
  127. package/src/blocks/pricing/pricing-table.tsx +173 -0
  128. package/src/blocks/pricing/pricing-types.ts +34 -0
  129. package/src/blocks/product-card/index.ts +2 -0
  130. package/src/blocks/product-card/product-card-types.ts +35 -0
  131. package/src/blocks/product-card/product-card.tsx +183 -0
  132. package/src/blocks/table/data-table-block.tsx +313 -0
  133. package/src/blocks/table/data-table-filter-menu.tsx +48 -0
  134. package/src/blocks/table/data-table-icon-menu-trigger.tsx +44 -0
  135. package/src/blocks/table/data-table-menu-content.tsx +32 -0
  136. package/src/blocks/table/data-table-pagination.tsx +149 -0
  137. package/src/blocks/table/data-table-row-actions.tsx +53 -0
  138. package/src/blocks/table/data-table-status.tsx +42 -0
  139. package/src/blocks/table/data-table-toolbar.tsx +124 -0
  140. package/src/blocks/table/data-table-totals.tsx +31 -0
  141. package/src/blocks/table/index.ts +13 -0
  142. package/src/blocks/workspace/index.ts +19 -0
  143. package/src/blocks/workspace/workspace-action-card.tsx +73 -0
  144. package/src/blocks/workspace/workspace-application-header.tsx +67 -0
  145. package/src/blocks/workspace/workspace-entity-card.tsx +48 -0
  146. package/src/blocks/workspace/workspace-health-summary.tsx +15 -0
  147. package/src/blocks/workspace/workspace-metric-card.tsx +97 -0
  148. package/src/blocks/workspace/workspace-page-header.tsx +43 -0
  149. package/src/blocks/workspace/workspace-publish-status.tsx +15 -0
  150. package/src/blocks/workspace/workspace-route-checklist.tsx +28 -0
  151. package/src/blocks/workspace/workspace-runtime-status.tsx +48 -0
  152. package/src/blocks/workspace/workspace-section-card.tsx +42 -0
  153. package/src/components/accordion.tsx +65 -0
  154. package/src/components/alert-dialog.tsx +160 -0
  155. package/src/components/alert.tsx +68 -0
  156. package/src/components/aspect-ratio.tsx +22 -0
  157. package/src/components/attachment.tsx +195 -0
  158. package/src/components/avatar.tsx +90 -0
  159. package/src/components/badge.tsx +55 -0
  160. package/src/components/breadcrumb.tsx +100 -0
  161. package/src/components/bubble.tsx +123 -0
  162. package/src/components/button-group.tsx +79 -0
  163. package/src/components/button.tsx +71 -0
  164. package/src/components/calendar.tsx +185 -0
  165. package/src/components/card.tsx +100 -0
  166. package/src/components/carousel.tsx +229 -0
  167. package/src/components/chart.tsx +338 -0
  168. package/src/components/checkbox.tsx +27 -0
  169. package/src/components/collapsible.tsx +15 -0
  170. package/src/components/combobox.tsx +269 -0
  171. package/src/components/command.tsx +181 -0
  172. package/src/components/compact-model-switcher.tsx +128 -0
  173. package/src/components/context-menu.tsx +244 -0
  174. package/src/components/dialog.tsx +138 -0
  175. package/src/components/direction.tsx +1 -0
  176. package/src/components/drawer.tsx +208 -0
  177. package/src/components/dropdown-menu.tsx +257 -0
  178. package/src/components/empty.tsx +93 -0
  179. package/src/components/field.tsx +232 -0
  180. package/src/components/hover-card.tsx +45 -0
  181. package/src/components/input-group.tsx +146 -0
  182. package/src/components/input-otp.tsx +83 -0
  183. package/src/components/input.tsx +19 -0
  184. package/src/components/item.tsx +188 -0
  185. package/src/components/kbd.tsx +26 -0
  186. package/src/components/label.tsx +17 -0
  187. package/src/components/markdown-content.tsx +113 -0
  188. package/src/components/marker.tsx +67 -0
  189. package/src/components/menubar.tsx +267 -0
  190. package/src/components/message-scroller.tsx +91 -0
  191. package/src/components/message.tsx +84 -0
  192. package/src/components/native-select.tsx +54 -0
  193. package/src/components/navigation-menu.tsx +160 -0
  194. package/src/components/pagination.tsx +118 -0
  195. package/src/components/popover.tsx +74 -0
  196. package/src/components/progress.tsx +82 -0
  197. package/src/components/questionnaire.tsx +150 -0
  198. package/src/components/radio-group.tsx +35 -0
  199. package/src/components/resizable.tsx +41 -0
  200. package/src/components/rich-text-editor.tsx +604 -0
  201. package/src/components/scroll-area.tsx +47 -0
  202. package/src/components/select.tsx +189 -0
  203. package/src/components/separator.tsx +18 -0
  204. package/src/components/sheet.tsx +125 -0
  205. package/src/components/sidebar.tsx +693 -0
  206. package/src/components/skeleton.tsx +13 -0
  207. package/src/components/slider.tsx +51 -0
  208. package/src/components/sonner.tsx +45 -0
  209. package/src/components/sparkline.tsx +231 -0
  210. package/src/components/spinner.tsx +20 -0
  211. package/src/components/status-badge.tsx +114 -0
  212. package/src/components/switch.tsx +31 -0
  213. package/src/components/table.tsx +91 -0
  214. package/src/components/tabs.tsx +72 -0
  215. package/src/components/textarea.tsx +17 -0
  216. package/src/components/toast.tsx +222 -0
  217. package/src/components/toggle-group.tsx +85 -0
  218. package/src/components/toggle.tsx +42 -0
  219. package/src/components/tooltip.tsx +53 -0
  220. package/src/design-system/README.md +55 -0
  221. package/src/design-system/action-intents.ts +21 -0
  222. package/src/design-system/agent-manifest.ts +83 -0
  223. package/src/design-system/block-registry.ts +272 -0
  224. package/src/design-system/component-registry.ts +142 -0
  225. package/src/design-system/contracts.ts +69 -0
  226. package/src/design-system/defaults.ts +3 -0
  227. package/src/design-system/index.ts +29 -0
  228. package/src/design-system/mcp-server.ts +156 -0
  229. package/src/design-system/page-registry.ts +74 -0
  230. package/src/design-system/selection.ts +67 -0
  231. package/src/design-system/template-registry.ts +33 -0
  232. package/src/features/interface-topology/index.ts +14 -0
  233. package/src/features/interface-topology/interface-topology.types.ts +40 -0
  234. package/src/features/interface-topology/topology-control.tsx +18 -0
  235. package/src/features/interface-topology/topology-inspector.tsx +228 -0
  236. package/src/features/interface-topology/topology-marker.tsx +47 -0
  237. package/src/features/interface-topology/topology-region.tsx +44 -0
  238. package/src/features/interface-topology/use-interface-topology.ts +178 -0
  239. package/src/hooks/use-mobile.ts +19 -0
  240. package/src/hooks/use-scroll-follow.ts +22 -0
  241. package/src/index.ts +11 -0
  242. package/src/layouts/README.md +65 -0
  243. package/src/layouts/agent-workspace/agent-activity-rail.tsx +101 -0
  244. package/src/layouts/agent-workspace/agent-workspace.tsx +27 -0
  245. package/src/layouts/agent-workspace/agent-workspace.types.ts +28 -0
  246. package/src/layouts/agent-workspace/index.ts +7 -0
  247. package/src/layouts/blog-header/blog-header-types.ts +25 -0
  248. package/src/layouts/blog-header/blog-header.tsx +172 -0
  249. package/src/layouts/blog-header/index.ts +2 -0
  250. package/src/layouts/documentation-workspace/README.md +8 -0
  251. package/src/layouts/documentation-workspace/documentation-workspace.tsx +34 -0
  252. package/src/layouts/documentation-workspace/index.ts +1 -0
  253. package/src/layouts/ecommerce-header/ecommerce-actions.tsx +89 -0
  254. package/src/layouts/ecommerce-header/ecommerce-announcement.tsx +43 -0
  255. package/src/layouts/ecommerce-header/ecommerce-drawer.tsx +97 -0
  256. package/src/layouts/ecommerce-header/ecommerce-header-types.ts +59 -0
  257. package/src/layouts/ecommerce-header/ecommerce-header.tsx +47 -0
  258. package/src/layouts/ecommerce-header/ecommerce-navigation.tsx +98 -0
  259. package/src/layouts/ecommerce-header/ecommerce-search.tsx +86 -0
  260. package/src/layouts/ecommerce-header/index.ts +2 -0
  261. package/src/layouts/main-workspace/index.ts +28 -0
  262. package/src/layouts/mdi/index.ts +1 -0
  263. package/src/layouts/mdi/mdi.tsx +20 -0
  264. package/src/layouts/mdi-main/index.ts +27 -0
  265. package/src/layouts/mdi-main/mdi-app-catalog.generated.ts +159 -0
  266. package/src/layouts/mdi-main/mdi-app-catalog.ts +76 -0
  267. package/src/layouts/mdi-main/mdi-app-switcher.tsx +107 -0
  268. package/src/layouts/mdi-main/mdi-feature-settings.tsx +135 -0
  269. package/src/layouts/mdi-main/mdi-global-search.tsx +192 -0
  270. package/src/layouts/mdi-main/mdi-main.tsx +241 -0
  271. package/src/layouts/mdi-main/mdi-notifications-menu.tsx +197 -0
  272. package/src/layouts/mdi-main/mdi-profile-menu.tsx +79 -0
  273. package/src/layouts/mdi-main/mdi-sidebar-navigation.tsx +226 -0
  274. package/src/layouts/mdi-main/mdi-sidebar.tsx +110 -0
  275. package/src/layouts/mdi-main/mdi-status-bar.tsx +26 -0
  276. package/src/layouts/mdi-main/mdi-top-menu-control.ts +4 -0
  277. package/src/layouts/mdi-main/mdi-top-menu.tsx +117 -0
  278. package/src/layouts/mdi-main/mdi-topology.tsx +297 -0
  279. package/src/layouts/mdi-main/mdi-tweak-panel.tsx +104 -0
  280. package/src/layouts/mdi-main/mdi-types.ts +131 -0
  281. package/src/layouts/mdi-main/use-mdi-features.ts +36 -0
  282. package/src/layouts/mdi-main/use-mdi-sidebar-state.ts +59 -0
  283. package/src/layouts/site-header/announcement-bar.tsx +55 -0
  284. package/src/layouts/site-header/category-strip.tsx +41 -0
  285. package/src/layouts/site-header/index.ts +16 -0
  286. package/src/layouts/site-header/main-navbar.tsx +179 -0
  287. package/src/layouts/site-header/mobile-drawer.tsx +140 -0
  288. package/src/layouts/site-header/site-header-types.ts +63 -0
  289. package/src/layouts/site-header/site-header.tsx +58 -0
  290. package/src/lib/random-id.ts +19 -0
  291. package/src/lib/utils.ts +6 -0
  292. package/src/providers/pdf-provider.ts +137 -0
  293. package/src/styles/globals.css +374 -0
  294. package/src/templates/README.md +12 -0
  295. package/src/templates/dashboard-01/components/app-sidebar.tsx +177 -0
  296. package/src/templates/dashboard-01/components/chart-area-interactive.tsx +276 -0
  297. package/src/templates/dashboard-01/components/data-table-cell-viewer.tsx +213 -0
  298. package/src/templates/dashboard-01/components/data-table.tsx +577 -0
  299. package/src/templates/dashboard-01/components/nav-documents.tsx +79 -0
  300. package/src/templates/dashboard-01/components/nav-main.tsx +55 -0
  301. package/src/templates/dashboard-01/components/nav-secondary.tsx +39 -0
  302. package/src/templates/dashboard-01/components/nav-user.tsx +97 -0
  303. package/src/templates/dashboard-01/components/section-cards.tsx +99 -0
  304. package/src/templates/dashboard-01/components/site-header.tsx +14 -0
  305. package/src/templates/dashboard-01/data.json +614 -0
  306. package/src/templates/dashboard-01/index.ts +7 -0
  307. package/src/templates/documentation-sidebar/app-sidebar.tsx +95 -0
  308. package/src/templates/documentation-sidebar/index.ts +2 -0
  309. package/src/templates/sidebar-07/components/app-sidebar.tsx +175 -0
  310. package/src/templates/sidebar-07/components/nav-main.tsx +64 -0
  311. package/src/templates/sidebar-07/components/nav-projects.tsx +79 -0
  312. package/src/templates/sidebar-07/components/nav-user.tsx +105 -0
  313. package/src/templates/sidebar-07/components/team-switcher.tsx +94 -0
  314. package/src/templates/sidebar-07/index.ts +1 -0
  315. package/src/templates/ui-page/index.ts +7 -0
  316. package/src/templates/ui-page/ui-browser-frame.tsx +27 -0
  317. package/src/templates/ui-page/ui-template-code.tsx +48 -0
  318. package/src/templates/ui-page/ui-template-header.tsx +87 -0
  319. package/src/templates/ui-page/ui-template-navigation.tsx +60 -0
  320. package/src/templates/ui-page/ui-template-page.tsx +97 -0
  321. package/src/theme/index.ts +12 -0
  322. package/src/theme/theme-config.ts +30 -0
  323. package/src/theme/theme-provider.tsx +142 -0
  324. package/src/theme/theme-selector.tsx +75 -0
  325. package/src/tokens/index.ts +15 -0
  326. package/src/vite-env.d.ts +3 -0
@@ -0,0 +1,21 @@
1
+ export type StoreCoupon = {
2
+ readonly applicableCategory?: string
3
+ readonly code: string
4
+ readonly description: string
5
+ readonly discountText: string
6
+ readonly expiresAt: string
7
+ readonly id: string
8
+ readonly isApplied?: boolean
9
+ readonly minimumOrderValue?: number
10
+ readonly terms?: string
11
+ readonly title: string
12
+ }
13
+
14
+ export type CouponWalletProps = {
15
+ readonly appliedCouponId?: string
16
+ readonly className?: string
17
+ readonly coupons: readonly StoreCoupon[]
18
+ readonly onApplyCoupon?: (code: string) => void
19
+ readonly onCopyCode?: (code: string) => void
20
+ readonly onRemoveCoupon?: () => void
21
+ }
@@ -0,0 +1,154 @@
1
+ import { useState } from 'react'
2
+ import { CheckIcon, CopyIcon, SparklesIcon, TagIcon, TicketIcon } from 'lucide-react'
3
+ import { cn } from '../../../lib/utils'
4
+ import { Button } from '../../../components/button'
5
+ import { Badge } from '../../../components/badge'
6
+ import type { CouponWalletProps } from './coupon-wallet-types'
7
+
8
+ export function CouponWallet({
9
+ appliedCouponId,
10
+ className,
11
+ coupons,
12
+ onApplyCoupon,
13
+ onCopyCode,
14
+ onRemoveCoupon,
15
+ }: CouponWalletProps) {
16
+ const [copiedCode, setCopiedCode] = useState<string | null>(null)
17
+ const [customCode, setCustomCode] = useState('')
18
+
19
+ const handleCopy = (code: string) => {
20
+ navigator.clipboard?.writeText(code)
21
+ setCopiedCode(code)
22
+ onCopyCode?.(code)
23
+ setTimeout(() => setCopiedCode(null), 2000)
24
+ }
25
+
26
+ return (
27
+ <div className={cn('space-y-6', className)}>
28
+ {/* Top Input for manual code entry */}
29
+ <div className="flex flex-col sm:flex-row gap-2 rounded-2xl border border-border/80 bg-card p-4 shadow-xs">
30
+ <div className="relative flex-1">
31
+ <TagIcon className="size-4 text-muted-foreground absolute left-3 top-1/2 -translate-y-1/2" />
32
+ <input
33
+ type="text"
34
+ value={customCode}
35
+ onChange={(e) => setCustomCode(e.target.value.toUpperCase())}
36
+ placeholder="Have a promo code? Enter here..."
37
+ className="w-full rounded-xl border border-input bg-muted/20 pl-9 pr-3 py-2 text-xs font-mono uppercase placeholder:font-sans placeholder:normal-case focus:outline-none focus:ring-1 focus:ring-primary"
38
+ />
39
+ </div>
40
+ <Button
41
+ size="sm"
42
+ disabled={!customCode.trim()}
43
+ onClick={() => {
44
+ onApplyCoupon?.(customCode)
45
+ setCustomCode('')
46
+ }}
47
+ className="text-xs"
48
+ >
49
+ Apply Promo
50
+ </Button>
51
+ </div>
52
+
53
+ {/* Available Coupons Grid */}
54
+ <div className="space-y-3">
55
+ <div className="flex items-center justify-between">
56
+ <div className="flex items-center gap-2">
57
+ <TicketIcon className="size-4 text-primary" />
58
+ <h4 className="text-sm font-bold text-foreground">Available Coupons & Vouchers</h4>
59
+ </div>
60
+ <span className="text-xs text-muted-foreground">{coupons.length} vouchers</span>
61
+ </div>
62
+
63
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
64
+ {coupons.map((coupon) => {
65
+ const isApplied = appliedCouponId === coupon.id
66
+ const isCopied = copiedCode === coupon.code
67
+
68
+ return (
69
+ <div
70
+ key={coupon.id}
71
+ className={cn(
72
+ 'relative flex flex-col justify-between overflow-hidden rounded-2xl border p-4 shadow-xs transition-all',
73
+ isApplied
74
+ ? 'border-primary bg-primary/5 ring-1 ring-primary'
75
+ : 'border-border/80 bg-card hover:border-border',
76
+ )}
77
+ >
78
+ {/* Coupon Scallop Cutouts */}
79
+ <div className="absolute -left-2 top-1/2 -translate-y-1/2 size-4 rounded-full bg-background border-r border-border" />
80
+ <div className="absolute -right-2 top-1/2 -translate-y-1/2 size-4 rounded-full bg-background border-l border-border" />
81
+
82
+ <div className="space-y-2">
83
+ <div className="flex items-start justify-between gap-2">
84
+ <div>
85
+ <span className="text-base font-black text-primary tracking-tight">
86
+ {coupon.discountText}
87
+ </span>
88
+ <h5 className="text-xs font-bold text-foreground mt-0.5">{coupon.title}</h5>
89
+ </div>
90
+ {isApplied ? (
91
+ <Badge variant="default" className="gap-1 text-[10px] font-bold">
92
+ <SparklesIcon className="size-3" />
93
+ <span>Applied</span>
94
+ </Badge>
95
+ ) : (
96
+ <span className="text-[10px] text-muted-foreground font-semibold">
97
+ Expires {coupon.expiresAt}
98
+ </span>
99
+ )}
100
+ </div>
101
+
102
+ <p className="text-xs text-muted-foreground">{coupon.description}</p>
103
+
104
+ {coupon.minimumOrderValue && (
105
+ <div className="text-[11px] text-muted-foreground/90">
106
+ Min. spend: <strong>${coupon.minimumOrderValue}</strong>
107
+ </div>
108
+ )}
109
+ </div>
110
+
111
+ {/* Bottom Actions */}
112
+ <div className="mt-4 pt-3 border-t border-border/60 border-dashed flex items-center justify-between gap-2">
113
+ {/* Code pill */}
114
+ <button
115
+ type="button"
116
+ onClick={() => handleCopy(coupon.code)}
117
+ className="flex items-center gap-1.5 rounded-lg border border-border/80 bg-muted/40 px-2.5 py-1 text-xs font-mono font-bold text-foreground hover:bg-muted transition-colors"
118
+ >
119
+ <span>{coupon.code}</span>
120
+ {isCopied ? (
121
+ <CheckIcon className="size-3 text-emerald-600" />
122
+ ) : (
123
+ <CopyIcon className="size-3 text-muted-foreground" />
124
+ )}
125
+ </button>
126
+
127
+ {isApplied ? (
128
+ <Button
129
+ size="sm"
130
+ variant="ghost"
131
+ className="h-7 text-xs text-destructive hover:bg-destructive/10"
132
+ onClick={onRemoveCoupon}
133
+ >
134
+ Remove
135
+ </Button>
136
+ ) : (
137
+ <Button
138
+ size="sm"
139
+ variant="outline"
140
+ className="h-7 text-xs"
141
+ onClick={() => onApplyCoupon?.(coupon.code)}
142
+ >
143
+ Apply Code
144
+ </Button>
145
+ )}
146
+ </div>
147
+ </div>
148
+ )
149
+ })}
150
+ </div>
151
+ </div>
152
+ </div>
153
+ )
154
+ }
@@ -0,0 +1,2 @@
1
+ export * from './coupon-wallet'
2
+ export * from './coupon-wallet-types'
@@ -0,0 +1,20 @@
1
+ export type DeliveryMilestone = {
2
+ readonly date?: string
3
+ readonly description?: string
4
+ readonly id: string
5
+ readonly location?: string
6
+ readonly status: 'completed' | 'current' | 'pending'
7
+ readonly time?: string
8
+ readonly title: string
9
+ }
10
+
11
+ export type DeliveryTrackerProps = {
12
+ readonly carrierName?: string
13
+ readonly className?: string
14
+ readonly deliveryAddress?: string
15
+ readonly estimatedDelivery: string
16
+ readonly milestones: readonly DeliveryMilestone[]
17
+ readonly orderId: string
18
+ readonly onTrackCarrier?: () => void
19
+ readonly trackingNumber: string
20
+ }
@@ -0,0 +1,169 @@
1
+ import { CheckCircle2Icon, ClockIcon, ExternalLinkIcon, MapPinIcon, TruckIcon } from 'lucide-react'
2
+ import { cn } from '../../../lib/utils'
3
+ import { Button } from '../../../components/button'
4
+ import { Badge } from '../../../components/badge'
5
+ import type { DeliveryTrackerProps } from './delivery-tracker-types'
6
+
7
+ export function DeliveryTracker({
8
+ carrierName = 'FedEx Express',
9
+ className,
10
+ deliveryAddress,
11
+ estimatedDelivery,
12
+ milestones,
13
+ onTrackCarrier,
14
+ orderId,
15
+ trackingNumber,
16
+ }: DeliveryTrackerProps) {
17
+ const currentMilestone =
18
+ milestones.find((m) => m.status === 'current') ?? milestones[milestones.length - 1]
19
+
20
+ return (
21
+ <div
22
+ className={cn(
23
+ 'space-y-6 rounded-2xl border border-border/80 bg-card p-6 shadow-xs',
24
+ className,
25
+ )}
26
+ >
27
+ {/* Header Info */}
28
+ <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 border-b border-border/60 pb-5">
29
+ <div>
30
+ <div className="flex items-center gap-2">
31
+ <span className="text-xs font-semibold text-muted-foreground">Order #{orderId}</span>
32
+ <Badge variant="secondary" className="text-[10px] font-bold">
33
+ {carrierName}
34
+ </Badge>
35
+ </div>
36
+ <h3 className="text-lg font-bold text-foreground mt-0.5">
37
+ Estimated Delivery: <span className="text-primary">{estimatedDelivery}</span>
38
+ </h3>
39
+ <p className="text-xs text-muted-foreground mt-0.5">
40
+ Tracking Number:{' '}
41
+ <span className="font-mono font-semibold text-foreground">{trackingNumber}</span>
42
+ </p>
43
+ </div>
44
+
45
+ {onTrackCarrier && (
46
+ <Button
47
+ size="sm"
48
+ variant="outline"
49
+ className="gap-1.5 text-xs self-start sm:self-auto"
50
+ onClick={onTrackCarrier}
51
+ >
52
+ <span>Track on {carrierName}</span>
53
+ <ExternalLinkIcon className="size-3.5" />
54
+ </Button>
55
+ )}
56
+ </div>
57
+
58
+ {/* Horizontal Milestone Tracker */}
59
+ <div className="py-2">
60
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
61
+ {milestones.map((step, idx) => {
62
+ const isCompleted = step.status === 'completed'
63
+ const isCurrent = step.status === 'current'
64
+
65
+ return (
66
+ <div key={step.id} className="relative flex flex-col items-start space-y-2">
67
+ {/* Step indicator circle */}
68
+ <div className="flex items-center w-full">
69
+ <div
70
+ className={cn(
71
+ 'flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-bold transition-all',
72
+ isCompleted && 'bg-emerald-600 text-white',
73
+ isCurrent &&
74
+ 'bg-primary text-primary-foreground ring-4 ring-primary/20 animate-pulse',
75
+ !isCompleted && !isCurrent && 'bg-muted text-muted-foreground',
76
+ )}
77
+ >
78
+ {isCompleted ? (
79
+ <CheckCircle2Icon className="size-4" />
80
+ ) : isCurrent ? (
81
+ <TruckIcon className="size-4" />
82
+ ) : (
83
+ <span>{idx + 1}</span>
84
+ )}
85
+ </div>
86
+ {idx < milestones.length - 1 && (
87
+ <div
88
+ className={cn(
89
+ 'h-1 w-full ml-2 rounded-full hidden sm:block',
90
+ isCompleted ? 'bg-emerald-600' : 'bg-border/60',
91
+ )}
92
+ />
93
+ )}
94
+ </div>
95
+
96
+ <div className="text-left space-y-0.5">
97
+ <h5
98
+ className={cn(
99
+ 'text-xs font-bold',
100
+ isCurrent ? 'text-primary' : 'text-foreground',
101
+ )}
102
+ >
103
+ {step.title}
104
+ </h5>
105
+ {step.date && <p className="text-[11px] text-muted-foreground">{step.date}</p>}
106
+ </div>
107
+ </div>
108
+ )
109
+ })}
110
+ </div>
111
+ </div>
112
+
113
+ {/* Status Highlights & Destination */}
114
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4 rounded-xl border border-border/60 bg-muted/20 p-4 text-xs">
115
+ <div className="space-y-1">
116
+ <div className="flex items-center gap-1.5 font-bold text-foreground">
117
+ <ClockIcon className="size-3.5 text-primary" />
118
+ <span>Latest Update</span>
119
+ </div>
120
+ <p className="text-muted-foreground">{currentMilestone?.description ?? 'In transit'}</p>
121
+ {currentMilestone?.location && (
122
+ <p className="text-[11px] text-muted-foreground/80 font-medium">
123
+ Location: {currentMilestone.location}
124
+ </p>
125
+ )}
126
+ </div>
127
+
128
+ {deliveryAddress && (
129
+ <div className="space-y-1 md:border-l md:border-border/60 md:pl-4">
130
+ <div className="flex items-center gap-1.5 font-bold text-foreground">
131
+ <MapPinIcon className="size-3.5 text-primary" />
132
+ <span>Destination Address</span>
133
+ </div>
134
+ <p className="text-muted-foreground">{deliveryAddress}</p>
135
+ </div>
136
+ )}
137
+ </div>
138
+
139
+ {/* Detailed Tracking Events List */}
140
+ <div className="space-y-3 pt-2">
141
+ <h5 className="text-xs font-bold text-foreground uppercase tracking-wider">
142
+ Tracking History
143
+ </h5>
144
+ <div className="space-y-3 border-l-2 border-border/80 pl-4 ml-1">
145
+ {milestones.map((m) => (
146
+ <div key={m.id} className="relative space-y-0.5 text-xs">
147
+ <div
148
+ className={cn(
149
+ 'absolute -left-[21px] top-1 size-2 rounded-full',
150
+ m.status === 'completed'
151
+ ? 'bg-emerald-600'
152
+ : m.status === 'current'
153
+ ? 'bg-primary ring-2 ring-primary/30'
154
+ : 'bg-muted-foreground/40',
155
+ )}
156
+ />
157
+ <div className="flex items-baseline justify-between gap-2">
158
+ <span className="font-semibold text-foreground">{m.title}</span>
159
+ <span className="text-[11px] text-muted-foreground">{m.time ?? m.date}</span>
160
+ </div>
161
+ {m.description && <p className="text-muted-foreground">{m.description}</p>}
162
+ {m.location && <p className="text-[10px] text-muted-foreground/70">{m.location}</p>}
163
+ </div>
164
+ ))}
165
+ </div>
166
+ </div>
167
+ </div>
168
+ )
169
+ }
@@ -0,0 +1,2 @@
1
+ export * from './delivery-tracker'
2
+ export * from './delivery-tracker-types'
@@ -0,0 +1,12 @@
1
+ export * from './cart'
2
+ export * from './categories'
3
+ export * from './checkout'
4
+ export * from './comparison'
5
+ export * from './coupon-wallet'
6
+ export * from './delivery-tracker'
7
+ export * from './payment-methods'
8
+ export * from './price-history'
9
+ export * from './reviews'
10
+ export * from './wishlist'
11
+ export * from '../product-card'
12
+ export * from '../pricing'
@@ -0,0 +1,2 @@
1
+ export * from './payment-method-selector'
2
+ export * from './payment-methods-types'
@@ -0,0 +1,224 @@
1
+ import { useState } from 'react'
2
+ import {
3
+ BanknoteIcon,
4
+ CreditCardIcon,
5
+ PlusIcon,
6
+ QrCodeIcon,
7
+ ShieldCheckIcon,
8
+ WalletIcon,
9
+ } from 'lucide-react'
10
+ import { cn } from '../../../lib/utils'
11
+ import { Button } from '../../../components/button'
12
+ import { Badge } from '../../../components/badge'
13
+ import type { PaymentMethodSelectorProps } from './payment-methods-types'
14
+
15
+ export function PaymentMethodSelector({
16
+ allowCOD = true,
17
+ className,
18
+ onAddNewCard,
19
+ onSelectMethod,
20
+ savedCards,
21
+ selectedMethod: initialMethod = 'card',
22
+ }: PaymentMethodSelectorProps) {
23
+ const [method, setMethod] = useState<'card' | 'upi' | 'wallet' | 'cod'>(initialMethod)
24
+ const [selectedCardId, setSelectedCardId] = useState<string>(
25
+ savedCards.find((c) => c.isDefault)?.id ?? savedCards[0]?.id ?? '',
26
+ )
27
+ const [cvv, setCvv] = useState('')
28
+ const [upiId, setUpiId] = useState('')
29
+
30
+ const handleMethodChange = (newMethod: 'card' | 'upi' | 'wallet' | 'cod') => {
31
+ setMethod(newMethod)
32
+ onSelectMethod?.(newMethod, { cardId: selectedCardId, upiId })
33
+ }
34
+
35
+ return (
36
+ <div
37
+ className={cn(
38
+ 'space-y-6 rounded-2xl border border-border/80 bg-card p-6 shadow-xs',
39
+ className,
40
+ )}
41
+ >
42
+ <div className="flex items-center justify-between border-b border-border/60 pb-4">
43
+ <div>
44
+ <h3 className="text-base font-bold text-foreground">Payment Options</h3>
45
+ <p className="text-xs text-muted-foreground">
46
+ Select how you would like to complete your purchase.
47
+ </p>
48
+ </div>
49
+ <div className="flex items-center gap-1.5 text-xs text-emerald-600 font-semibold">
50
+ <ShieldCheckIcon className="size-4" />
51
+ <span>PCI-DSS Compliant</span>
52
+ </div>
53
+ </div>
54
+
55
+ {/* Main Method Selector Tabs */}
56
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
57
+ {[
58
+ { id: 'card', label: 'Cards', icon: CreditCardIcon },
59
+ { id: 'upi', label: 'UPI / QR', icon: QrCodeIcon },
60
+ { id: 'wallet', label: 'Wallets', icon: WalletIcon },
61
+ ...(allowCOD ? [{ id: 'cod', label: 'Cash on Delivery', icon: BanknoteIcon }] : []),
62
+ ].map((m) => {
63
+ const Icon = m.icon
64
+ const isSelected = method === m.id
65
+
66
+ return (
67
+ <button
68
+ key={m.id}
69
+ type="button"
70
+ onClick={() => handleMethodChange(m.id as 'card' | 'upi' | 'wallet' | 'cod')}
71
+ className={cn(
72
+ 'flex flex-col items-center justify-center p-3 rounded-xl border text-xs font-bold transition-all gap-2',
73
+ isSelected
74
+ ? 'border-primary bg-primary/10 text-primary ring-1 ring-primary shadow-xs'
75
+ : 'border-border/80 bg-muted/20 text-muted-foreground hover:border-border hover:text-foreground',
76
+ )}
77
+ >
78
+ <Icon className="size-5" />
79
+ <span>{m.label}</span>
80
+ </button>
81
+ )
82
+ })}
83
+ </div>
84
+
85
+ {/* 1. Credit / Debit Cards Mode */}
86
+ {method === 'card' && (
87
+ <div className="space-y-4 pt-2">
88
+ <div className="flex items-center justify-between">
89
+ <span className="text-xs font-bold text-foreground">Your Saved Cards</span>
90
+ {onAddNewCard && (
91
+ <Button
92
+ size="sm"
93
+ variant="ghost"
94
+ className="h-7 text-xs gap-1"
95
+ onClick={onAddNewCard}
96
+ >
97
+ <PlusIcon className="size-3.5" />
98
+ <span>Add Card</span>
99
+ </Button>
100
+ )}
101
+ </div>
102
+
103
+ <div className="space-y-2.5">
104
+ {savedCards.map((card) => {
105
+ const isSelected = selectedCardId === card.id
106
+
107
+ return (
108
+ <div
109
+ key={card.id}
110
+ onClick={() => {
111
+ setSelectedCardId(card.id)
112
+ onSelectMethod?.('card', { cardId: card.id })
113
+ }}
114
+ className={cn(
115
+ 'flex flex-col sm:flex-row sm:items-center justify-between gap-3 p-3.5 rounded-xl border cursor-pointer transition-all text-xs',
116
+ isSelected
117
+ ? 'border-primary bg-primary/5 ring-1 ring-primary'
118
+ : 'border-border/80 bg-muted/10 hover:border-border',
119
+ )}
120
+ >
121
+ <div className="flex items-center gap-3">
122
+ <div className="flex size-9 items-center justify-center rounded-lg bg-background border border-border/80 font-mono font-bold uppercase text-[10px]">
123
+ {card.brand}
124
+ </div>
125
+ <div>
126
+ <div className="flex items-center gap-2 font-bold text-foreground">
127
+ <span>•••• •••• •••• {card.last4}</span>
128
+ {card.isDefault && (
129
+ <Badge variant="secondary" className="text-[10px] py-0 font-semibold">
130
+ Default
131
+ </Badge>
132
+ )}
133
+ </div>
134
+ <div className="text-[11px] text-muted-foreground mt-0.5">
135
+ {card.cardholderName} • Expires {card.expiryMonth}/{card.expiryYear}
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ {isSelected && (
141
+ <div
142
+ className="flex items-center gap-2 self-end sm:self-center"
143
+ onClick={(e) => e.stopPropagation()}
144
+ >
145
+ <span className="text-[11px] font-semibold text-foreground">CVV:</span>
146
+ <input
147
+ type="password"
148
+ maxLength={4}
149
+ placeholder="•••"
150
+ value={cvv}
151
+ onChange={(e) => setCvv(e.target.value)}
152
+ className="w-14 rounded border border-input bg-background px-2 py-1 text-center font-mono text-xs focus:outline-none focus:ring-1 focus:ring-primary"
153
+ />
154
+ </div>
155
+ )}
156
+ </div>
157
+ )
158
+ })}
159
+ </div>
160
+ </div>
161
+ )}
162
+
163
+ {/* 2. UPI / QR Mode */}
164
+ {method === 'upi' && (
165
+ <div className="space-y-3 rounded-xl border border-border/80 bg-muted/20 p-4 text-xs">
166
+ <div className="flex items-center gap-2 font-bold text-foreground">
167
+ <QrCodeIcon className="size-4 text-primary" />
168
+ <span>Instant UPI Payment</span>
169
+ </div>
170
+ <p className="text-muted-foreground">
171
+ Pay directly from Google Pay, PhonePe, Paytm, or BHIM.
172
+ </p>
173
+ <div className="flex gap-2 pt-1">
174
+ <input
175
+ type="text"
176
+ placeholder="e.g. mobileNumber@upi or user@okhdfcbank"
177
+ value={upiId}
178
+ onChange={(e) => setUpiId(e.target.value)}
179
+ className="flex-1 rounded-lg border border-input bg-background px-3 py-2 text-foreground focus:outline-none focus:ring-1 focus:ring-primary"
180
+ />
181
+ <Button
182
+ size="sm"
183
+ disabled={!upiId.includes('@')}
184
+ onClick={() => onSelectMethod?.('upi', { upiId })}
185
+ >
186
+ Verify UPI ID
187
+ </Button>
188
+ </div>
189
+ </div>
190
+ )}
191
+
192
+ {/* 3. Wallets Mode */}
193
+ {method === 'wallet' && (
194
+ <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 pt-1">
195
+ {['Apple Pay', 'Google Pay', 'PayPal'].map((wallet) => (
196
+ <button
197
+ key={wallet}
198
+ type="button"
199
+ onClick={() => onSelectMethod?.('wallet')}
200
+ className="flex items-center justify-center gap-2 p-4 rounded-xl border border-border/80 bg-muted/20 hover:border-primary hover:bg-primary/5 transition-all text-xs font-bold text-foreground"
201
+ >
202
+ <WalletIcon className="size-4 text-primary" />
203
+ <span>{wallet}</span>
204
+ </button>
205
+ ))}
206
+ </div>
207
+ )}
208
+
209
+ {/* 4. Cash on Delivery Mode */}
210
+ {method === 'cod' && (
211
+ <div className="rounded-xl border border-border/80 bg-muted/20 p-4 text-xs space-y-2">
212
+ <div className="flex items-center gap-2 font-bold text-foreground">
213
+ <BanknoteIcon className="size-4 text-primary" />
214
+ <span>Pay with Cash Upon Delivery</span>
215
+ </div>
216
+ <p className="text-muted-foreground">
217
+ You can pay the courier agent via cash or mobile QR scan at your doorstep. Please keep
218
+ exact change ready.
219
+ </p>
220
+ </div>
221
+ )}
222
+ </div>
223
+ )
224
+ }
@@ -0,0 +1,21 @@
1
+ export type SavedCard = {
2
+ readonly brand: 'visa' | 'mastercard' | 'amex' | 'discover'
3
+ readonly cardholderName: string
4
+ readonly expiryMonth: string
5
+ readonly expiryYear: string
6
+ readonly id: string
7
+ readonly isDefault?: boolean
8
+ readonly last4: string
9
+ }
10
+
11
+ export type PaymentMethodSelectorProps = {
12
+ readonly allowCOD?: boolean
13
+ readonly className?: string
14
+ readonly onAddNewCard?: () => void
15
+ readonly onSelectMethod?: (
16
+ method: 'card' | 'upi' | 'wallet' | 'cod',
17
+ details?: { cardId?: string; upiId?: string },
18
+ ) => void
19
+ readonly savedCards: readonly SavedCard[]
20
+ readonly selectedMethod?: 'card' | 'upi' | 'wallet' | 'cod'
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from './price-history-chart'
2
+ export * from './price-history-types'