@liorian/sdk 0.28.0-alpha.56010ca
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +483 -0
- package/package.json +94 -0
- package/schemas/module.schema.json +818 -0
- package/src/application/index.ts +3 -0
- package/src/application/module-instance.ts +36 -0
- package/src/application/service/auth-api-service.ts +291 -0
- package/src/application/service/auth-user.service.ts +108 -0
- package/src/application/service/index.ts +12 -0
- package/src/application/service/module-activation-api.service.ts +105 -0
- package/src/application/service/notifications-api-service.ts +38 -0
- package/src/application/service/notifications-push.service.ts +299 -0
- package/src/application/service/notifications-socket-service.ts +76 -0
- package/src/application/service/organizations-api-service.ts +104 -0
- package/src/application/service/otp-api-service.ts +11 -0
- package/src/application/service/storage-api-service.ts +77 -0
- package/src/application/service/storefront-api.service.ts +72 -0
- package/src/application/service/user-preferences-api.service.ts +57 -0
- package/src/domain/config/app.config.ts +35 -0
- package/src/domain/config/auth.config.ts +30 -0
- package/src/domain/config/index.ts +4 -0
- package/src/domain/config/logo.config.ts +17 -0
- package/src/domain/entities/activities.interface.ts +18 -0
- package/src/domain/entities/catalog.interface.ts +96 -0
- package/src/domain/entities/index.ts +13 -0
- package/src/domain/entities/media.ts +22 -0
- package/src/domain/entities/module-activation.interface.ts +173 -0
- package/src/domain/entities/module.interface.ts +101 -0
- package/src/domain/entities/notification.interface.ts +23 -0
- package/src/domain/entities/objectable.type.ts +3 -0
- package/src/domain/entities/organization.interface.ts +81 -0
- package/src/domain/entities/user-auth.interface.ts +17 -0
- package/src/domain/entities/user-phone.interface.ts +11 -0
- package/src/domain/entities/user-profile.interface.ts +23 -0
- package/src/domain/entities/user.interface.ts +79 -0
- package/src/domain/enums/coloring.enum.ts +6 -0
- package/src/domain/enums/domains.enum.ts +282 -0
- package/src/domain/enums/index.ts +8 -0
- package/src/domain/enums/module-category.enum.ts +57 -0
- package/src/domain/enums/module.enum.ts +97 -0
- package/src/domain/enums/routine.enum.ts +12 -0
- package/src/domain/enums/user-profile.enum.ts +25 -0
- package/src/domain/enums/user-status.enum.ts +7 -0
- package/src/domain/index.ts +6 -0
- package/src/domain/typing/auth-caches.ts +12 -0
- package/src/domain/typing/auth-oauth.types.ts +172 -0
- package/src/domain/typing/devise.ts +2 -0
- package/src/domain/typing/index.ts +10 -0
- package/src/domain/typing/response.ts +30 -0
- package/src/domain/typing/routine.types.ts +113 -0
- package/src/domain/typing/session.interface.ts +28 -0
- package/src/domain/typing/statisticals.ts +11 -0
- package/src/domain/typing/user-media-upload.ts +9 -0
- package/src/domain/typing/values.ts +6 -0
- package/src/index.tsx +168 -0
- package/src/infrastructure/capabilities/cache-storage/capability.ts +129 -0
- package/src/infrastructure/capabilities/cache-storage/enum.ts +5 -0
- package/src/infrastructure/capabilities/cache-storage/index.ts +4 -0
- package/src/infrastructure/capabilities/cache-storage/types.ts +13 -0
- package/src/infrastructure/capabilities/index.ts +3 -0
- package/src/infrastructure/capabilities/stackable/capability.ts +55 -0
- package/src/infrastructure/capabilities/stackable/index.ts +3 -0
- package/src/infrastructure/capabilities/stackable/types.ts +24 -0
- package/src/infrastructure/common-classname.constant.ts +4 -0
- package/src/infrastructure/data/countries.ts +208 -0
- package/src/infrastructure/data/gender.ts +5 -0
- package/src/infrastructure/data/index.ts +3 -0
- package/src/infrastructure/dataset/index.ts +3 -0
- package/src/infrastructure/dataset/sign-in.dataset.ts +21 -0
- package/src/infrastructure/dataset/sign-up.dataset.ts +64 -0
- package/src/infrastructure/hooks/index.ts +10 -0
- package/src/infrastructure/hooks/use-activity-lock-draft.ts +69 -0
- package/src/infrastructure/hooks/use-auth.ts +24 -0
- package/src/infrastructure/hooks/use-elastic-interaction.ts +180 -0
- package/src/infrastructure/hooks/use-is-desktop.ts +25 -0
- package/src/infrastructure/hooks/use-is-tauri.ts +17 -0
- package/src/infrastructure/hooks/use-mobile.ts +19 -0
- package/src/infrastructure/hooks/use-notifications.ts +128 -0
- package/src/infrastructure/hooks/use-recent-colors.ts +113 -0
- package/src/infrastructure/hooks/use-recent-modules.ts +76 -0
- package/src/infrastructure/index.tsx +11 -0
- package/src/infrastructure/library/design-system.ts +95 -0
- package/src/infrastructure/library/index.tsx +5 -0
- package/src/infrastructure/library/motion-utils.ts +77 -0
- package/src/infrastructure/library/motion.tsx +31 -0
- package/src/infrastructure/library/scroll-progress.tsx +93 -0
- package/src/infrastructure/providers/auth-guard.provider.tsx +47 -0
- package/src/infrastructure/providers/auth.provider.tsx +168 -0
- package/src/infrastructure/providers/index.tsx +8 -0
- package/src/infrastructure/providers/module-usage.provider.tsx +95 -0
- package/src/infrastructure/providers/modules-guard.provider.tsx +64 -0
- package/src/infrastructure/providers/modules-routines.provider.tsx +33 -0
- package/src/infrastructure/providers/modules-switcher.provider.tsx +25 -0
- package/src/infrastructure/providers/query.provider.tsx +27 -0
- package/src/infrastructure/routines/__tests__/routine.test.ts +368 -0
- package/src/infrastructure/routines/index.tsx +3 -0
- package/src/infrastructure/routines/routine.hook.ts +121 -0
- package/src/infrastructure/routines/routine.ts +283 -0
- package/src/infrastructure/routines/routine.tsx +283 -0
- package/src/infrastructure/stores/activity-lock.store.ts +22 -0
- package/src/infrastructure/stores/auth-user-connected.store.ts +24 -0
- package/src/infrastructure/stores/dataset.store.ts +106 -0
- package/src/infrastructure/stores/index.ts +6 -0
- package/src/infrastructure/stores/module.store.ts +266 -0
- package/src/infrastructure/stores/upload.store.ts +198 -0
- package/src/infrastructure/utilities/access-label.util.ts +158 -0
- package/src/infrastructure/utilities/activities.util.tsx +54 -0
- package/src/infrastructure/utilities/activity-lock.service.ts +263 -0
- package/src/infrastructure/utilities/activity-tracker.service.ts +205 -0
- package/src/infrastructure/utilities/api-service.ts +237 -0
- package/src/infrastructure/utilities/auth-logout.util.ts +23 -0
- package/src/infrastructure/utilities/classname.util.ts +7 -0
- package/src/infrastructure/utilities/encryption.service.ts +125 -0
- package/src/infrastructure/utilities/form-snapshot.service.ts +304 -0
- package/src/infrastructure/utilities/format.util.ts +40 -0
- package/src/infrastructure/utilities/index.tsx +23 -0
- package/src/infrastructure/utilities/media-label.service.ts +47 -0
- package/src/infrastructure/utilities/modules.ts +11 -0
- package/src/infrastructure/utilities/permission.util.ts +22 -0
- package/src/infrastructure/utilities/push-permission.util.ts +43 -0
- package/src/infrastructure/utilities/route-access.ts +38 -0
- package/src/infrastructure/utilities/socket-service.ts +123 -0
- package/src/infrastructure/utilities/sso-auth.util.ts +188 -0
- package/src/infrastructure/utilities/stringable.util.ts +16 -0
- package/src/infrastructure/utilities/strings.util.ts +18 -0
- package/src/infrastructure/utilities/tauri.util.ts +15 -0
- package/src/infrastructure/utilities/utils.ts +6 -0
- package/src/infrastructure/utilities/values.ts +5 -0
- package/src/presentation/8starlabs-ui/button.tsx +94 -0
- package/src/presentation/8starlabs-ui/flip-clock.tsx +368 -0
- package/src/presentation/8starlabs-ui/heatmap.tsx +430 -0
- package/src/presentation/8starlabs-ui/hooks/index.tsx +2 -0
- package/src/presentation/8starlabs-ui/hooks/use-mobile.ts +21 -0
- package/src/presentation/8starlabs-ui/index.tsx +20 -0
- package/src/presentation/8starlabs-ui/json-viewer.tsx +972 -0
- package/src/presentation/8starlabs-ui/marquee.tsx +134 -0
- package/src/presentation/8starlabs-ui/partition-bar.tsx +198 -0
- package/src/presentation/8starlabs-ui/scroll-fade.tsx +158 -0
- package/src/presentation/8starlabs-ui/status-indicator.tsx +86 -0
- package/src/presentation/8starlabs-ui/system-banner.tsx +50 -0
- package/src/presentation/8starlabs-ui/timeline.tsx +576 -0
- package/src/presentation/8starlabs-ui/transport-badge.tsx +249 -0
- package/src/presentation/8starlabs-ui/ui/copy-button.tsx +60 -0
- package/src/presentation/8starlabs-ui/ui/index.tsx +2 -0
- package/src/presentation/analytics-section.tsx +85 -0
- package/src/presentation/app-sidebar.tsx +234 -0
- package/src/presentation/charts/area-widget.chart-skeleton.tsx +61 -0
- package/src/presentation/charts/area-widget.chart.tsx +128 -0
- package/src/presentation/charts/chart-widgets.types.ts +81 -0
- package/src/presentation/charts/index.tsx +16 -0
- package/src/presentation/charts/line-widget.chart-skeleton.tsx +64 -0
- package/src/presentation/charts/line-widget.chart.tsx +105 -0
- package/src/presentation/charts/pie-widget.chart-skeleton.tsx +56 -0
- package/src/presentation/charts/pie-widget.chart.tsx +168 -0
- package/src/presentation/charts/radar-widget.chart-skeleton.tsx +67 -0
- package/src/presentation/charts/radar-widget.chart.tsx +80 -0
- package/src/presentation/charts/radial-stacked-widget.chart-skeleton.tsx +66 -0
- package/src/presentation/charts/radial-stacked-widget.chart.tsx +120 -0
- package/src/presentation/charts/radial-widget.chart-skeleton.tsx +61 -0
- package/src/presentation/charts/radial-widget.chart.tsx +87 -0
- package/src/presentation/charts/tooltip-widget.chart-skeleton.tsx +64 -0
- package/src/presentation/charts/tooltip-widget.chart.tsx +89 -0
- package/src/presentation/components/activity-actions.tsx +20 -0
- package/src/presentation/components/activity-container.tsx +55 -0
- package/src/presentation/components/activity-content.tsx +20 -0
- package/src/presentation/components/activity-descriptor-parser.tsx +37 -0
- package/src/presentation/components/activity-header.tsx +20 -0
- package/src/presentation/components/activity-loader.tsx +19 -0
- package/src/presentation/components/activity-title.tsx +32 -0
- package/src/presentation/components/activity.tsx +22 -0
- package/src/presentation/components/auth/index.tsx +4 -0
- package/src/presentation/components/auth/sso-callback.view.tsx +44 -0
- package/src/presentation/components/auth/sso-disconnect.view.tsx +41 -0
- package/src/presentation/components/auth/sso-sign-in.view.tsx +29 -0
- package/src/presentation/components/auth-lock-screen.tsx +309 -0
- package/src/presentation/components/auth-session.view.tsx +17 -0
- package/src/presentation/components/data-table.tsx +814 -0
- package/src/presentation/components/dynamic-icon.tsx +16 -0
- package/src/presentation/components/floating-upload.tsx +291 -0
- package/src/presentation/components/index.tsx +40 -0
- package/src/presentation/components/local-time.tsx +170 -0
- package/src/presentation/components/markdown-parser.tsx +201 -0
- package/src/presentation/components/message-scroller.tsx +131 -0
- package/src/presentation/components/module-first-access-config.view.tsx +181 -0
- package/src/presentation/components/module-first-access-pending.view.tsx +38 -0
- package/src/presentation/components/module-guard.tsx +34 -0
- package/src/presentation/components/modules-first-access.guard.tsx +88 -0
- package/src/presentation/components/modules-guard-forbidden.tsx +46 -0
- package/src/presentation/components/notification-details.modal.tsx +145 -0
- package/src/presentation/components/notification-item.tsx +127 -0
- package/src/presentation/components/notifications-popover.tsx +128 -0
- package/src/presentation/components/push-notifications.provider.tsx +65 -0
- package/src/presentation/components/upload-progress-dialog.tsx +140 -0
- package/src/presentation/components/waiting-bar.tsx +22 -0
- package/src/presentation/components/waiting-section.tsx +15 -0
- package/src/presentation/components/waiting.tsx +14 -0
- package/src/presentation/data-grid/data-grid-empty.tsx +24 -0
- package/src/presentation/data-grid/data-grid-search-engine.tsx +32 -0
- package/src/presentation/data-grid/data-grid.tsx +892 -0
- package/src/presentation/data-grid/index.tsx +4 -0
- package/src/presentation/form-screen.tsx +95 -0
- package/src/presentation/icons/custom.tsx +20 -0
- package/src/presentation/icons/glyphIcons.tsx +53 -0
- package/src/presentation/icons/icons.enum.ts +4 -0
- package/src/presentation/icons/icons.util.ts +6 -0
- package/src/presentation/icons/index.tsx +8 -0
- package/src/presentation/icons/lucide.tsx +17 -0
- package/src/presentation/icons/remix.tsx +33 -0
- package/src/presentation/icons/types.ts +27 -0
- package/src/presentation/index.tsx +45 -0
- package/src/presentation/modals/components/ModalBox.tsx +74 -0
- package/src/presentation/modals/components/ModalPortal.tsx +31 -0
- package/src/presentation/modals/components/ModalStepper.tsx +319 -0
- package/src/presentation/modals/components/ModalWrapper.tsx +65 -0
- package/src/presentation/modals/components/index.tsx +5 -0
- package/src/presentation/modals/hooks/index.ts +2 -0
- package/src/presentation/modals/hooks/useModal.ts +38 -0
- package/src/presentation/modals/index.tsx +5 -0
- package/src/presentation/modals/stores/index.ts +2 -0
- package/src/presentation/modals/stores/useModalStore.ts +90 -0
- package/src/presentation/modals/types/index.ts +2 -0
- package/src/presentation/modals/types/modal.type.ts +33 -0
- package/src/presentation/module-menubar.tsx +300 -0
- package/src/presentation/module-widget.tsx +233 -0
- package/src/presentation/nav-documents.tsx +89 -0
- package/src/presentation/nav-main.tsx +62 -0
- package/src/presentation/nav-secondary.tsx +41 -0
- package/src/presentation/nav-user.tsx +109 -0
- package/src/presentation/permission-action-badge.tsx +35 -0
- package/src/presentation/reui/index.tsx +3 -0
- package/src/presentation/reui/stepper.tsx +508 -0
- package/src/presentation/reui/timeline.tsx +226 -0
- package/src/presentation/sheets/index.tsx +2 -0
- package/src/presentation/sheets/legacy-sheet-header.tsx +0 -0
- package/src/presentation/sheets/legacy-sheet.tsx +37 -0
- package/src/presentation/size.enum.ts +19 -0
- package/src/presentation/system/index.tsx +3 -0
- package/src/presentation/system/logo.theme.tsx +21 -0
- package/src/presentation/system/types.ts +10 -0
- package/src/presentation/theme/index.tsx +6 -0
- package/src/presentation/theme/prefer-color-scheme.tsx +50 -0
- package/src/presentation/theme/switch-color-scheme.tsx +16 -0
- package/src/presentation/theme/theme-switcher-button.tsx +20 -0
- package/src/presentation/theme/theme.enum.ts +4 -0
- package/src/presentation/theme/theme.store.ts +87 -0
- package/src/presentation/themes/index.tsx +2 -0
- package/src/presentation/themes/katon/dashboard-layout.tsx +1080 -0
- package/src/presentation/themes/katon/edge-section.tsx +19 -0
- package/src/presentation/themes/katon/header-menubar.tsx +270 -0
- package/src/presentation/themes/katon/header-modules-available.tsx +44 -0
- package/src/presentation/themes/katon/header-modules-recents.tsx +52 -0
- package/src/presentation/themes/katon/header-modules-store.tsx +25 -0
- package/src/presentation/themes/katon/header-options.tsx +13 -0
- package/src/presentation/themes/katon/header-organization-select.tsx +146 -0
- package/src/presentation/themes/katon/header-routines.tsx +74 -0
- package/src/presentation/themes/katon/header-tasks-connected-user.tsx +150 -0
- package/src/presentation/themes/katon/index.tsx +16 -0
- package/src/presentation/themes/katon/main-wrapper.tsx +34 -0
- package/src/presentation/themes/katon/module-item-link.tsx +32 -0
- package/src/presentation/themes/katon/view-frame.tsx +25 -0
- package/src/presentation/themes/katon/view-helmet.tsx +53 -0
- package/src/presentation/themes/katon/view-status.tsx +32 -0
- package/src/presentation/themes/katon/view-wrapper.tsx +15 -0
- package/src/presentation/themes/katon/view.tsx +42 -0
- package/src/presentation/ui/accordion-multiselect.tsx +206 -0
- package/src/presentation/ui/accordion.tsx +81 -0
- package/src/presentation/ui/alert-dialog.tsx +199 -0
- package/src/presentation/ui/alert.tsx +76 -0
- package/src/presentation/ui/aspect-ratio.tsx +11 -0
- package/src/presentation/ui/attachment.tsx +204 -0
- package/src/presentation/ui/avatar.tsx +112 -0
- package/src/presentation/ui/badge.tsx +49 -0
- package/src/presentation/ui/breadcrumb.tsx +122 -0
- package/src/presentation/ui/bubble.tsx +125 -0
- package/src/presentation/ui/button-group.tsx +83 -0
- package/src/presentation/ui/button.tsx +87 -0
- package/src/presentation/ui/calendar.tsx +222 -0
- package/src/presentation/ui/card.tsx +106 -0
- package/src/presentation/ui/carousel.tsx +242 -0
- package/src/presentation/ui/chart.tsx +373 -0
- package/src/presentation/ui/checkbox.tsx +33 -0
- package/src/presentation/ui/clickable.tsx +58 -0
- package/src/presentation/ui/collapsible.tsx +33 -0
- package/src/presentation/ui/color-swatch-selector.tsx +81 -0
- package/src/presentation/ui/combobox.tsx +299 -0
- package/src/presentation/ui/command.tsx +195 -0
- package/src/presentation/ui/context-menu.tsx +263 -0
- package/src/presentation/ui/dialog.tsx +168 -0
- package/src/presentation/ui/direction.tsx +22 -0
- package/src/presentation/ui/drawer.tsx +134 -0
- package/src/presentation/ui/dropdown-menu.tsx +269 -0
- package/src/presentation/ui/empty.tsx +104 -0
- package/src/presentation/ui/field.tsx +238 -0
- package/src/presentation/ui/granularity-selector.tsx +58 -0
- package/src/presentation/ui/hover-card.tsx +44 -0
- package/src/presentation/ui/index.tsx +74 -0
- package/src/presentation/ui/input-group.tsx +156 -0
- package/src/presentation/ui/input-otp.tsx +87 -0
- package/src/presentation/ui/input.tsx +19 -0
- package/src/presentation/ui/item.tsx +196 -0
- package/src/presentation/ui/kpi-card.tsx +203 -0
- package/src/presentation/ui/label-selector.tsx +100 -0
- package/src/presentation/ui/label.tsx +24 -0
- package/src/presentation/ui/legacy-birth-date-input.tsx +43 -0
- package/src/presentation/ui/legacy-color-picker/index.tsx +42 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.content.tsx +37 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.context.tsx +42 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.hex-input.tsx +97 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.picker.tsx +266 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.presets.ts +22 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.quick-list.tsx +49 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.recent.tsx +43 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.swatches.tsx +111 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.trigger.tsx +128 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.tsx +110 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.types.ts +1 -0
- package/src/presentation/ui/legacy-color-picker/legacy-color-picker.utils.ts +114 -0
- package/src/presentation/ui/legacy-country-input.tsx +171 -0
- package/src/presentation/ui/legacy-gender-input.tsx +22 -0
- package/src/presentation/ui/legacy-input.tsx +106 -0
- package/src/presentation/ui/legacy-phone-input.tsx +213 -0
- package/src/presentation/ui/legacy-select-input.tsx +114 -0
- package/src/presentation/ui/legacy-text-area.tsx +111 -0
- package/src/presentation/ui/list-items.tsx +59 -0
- package/src/presentation/ui/marker.tsx +69 -0
- package/src/presentation/ui/media-player/index.tsx +12 -0
- package/src/presentation/ui/media-player/media-player.context.tsx +36 -0
- package/src/presentation/ui/media-player/media-player.tsx +167 -0
- package/src/presentation/ui/media-player/player-controls.tsx +207 -0
- package/src/presentation/ui/media-player/players/audio-player.tsx +78 -0
- package/src/presentation/ui/media-player/players/index.tsx +4 -0
- package/src/presentation/ui/media-player/players/video-player.tsx +193 -0
- package/src/presentation/ui/media-player/players/voice-note-player.tsx +108 -0
- package/src/presentation/ui/media-player/use-media-player.hook.ts +263 -0
- package/src/presentation/ui/menubar.tsx +281 -0
- package/src/presentation/ui/message.tsx +92 -0
- package/src/presentation/ui/navigation-menu.tsx +172 -0
- package/src/presentation/ui/pagination.tsx +129 -0
- package/src/presentation/ui/popover.tsx +89 -0
- package/src/presentation/ui/progress.tsx +31 -0
- package/src/presentation/ui/resizable.tsx +50 -0
- package/src/presentation/ui/select.tsx +192 -0
- package/src/presentation/ui/separator.tsx +28 -0
- package/src/presentation/ui/sheet.tsx +147 -0
- package/src/presentation/ui/sidebar.tsx +702 -0
- package/src/presentation/ui/skeleton.tsx +13 -0
- package/src/presentation/ui/slide-to-confirm.tsx +129 -0
- package/src/presentation/ui/slider.tsx +59 -0
- package/src/presentation/ui/sonner.tsx +58 -0
- package/src/presentation/ui/switch.tsx +33 -0
- package/src/presentation/ui/table.tsx +116 -0
- package/src/presentation/ui/tabs.tsx +90 -0
- package/src/presentation/ui/text-gradient.tsx +84 -0
- package/src/presentation/ui/textarea.tsx +18 -0
- package/src/presentation/ui/timeline-steps.tsx +235 -0
- package/src/presentation/ui/toggle-group.tsx +89 -0
- package/src/presentation/ui/toggle.tsx +47 -0
- package/src/presentation/ui/tooltip.tsx +57 -0
- package/src/presentation/uploading/index.tsx +3 -0
- package/src/presentation/uploading/media-upload-field.tsx +152 -0
- package/src/presentation/uploading/storage-media.tsx +210 -0
- package/src/styles.css +403 -0
- package/src/themes.css +1038 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import {useAuth} from "../../../infrastructure/hooks/use-auth";
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem,
|
|
7
|
+
DropdownMenuLabel, DropdownMenuSeparator,
|
|
8
|
+
DropdownMenuTrigger
|
|
9
|
+
} from "../../ui/dropdown-menu";
|
|
10
|
+
import {Avatar, AvatarFallback} from "../../ui/avatar";
|
|
11
|
+
import {StorageMedia} from "../../uploading/storage-media";
|
|
12
|
+
import {
|
|
13
|
+
BellIcon,
|
|
14
|
+
CircleUserRoundIcon,
|
|
15
|
+
CogIcon,
|
|
16
|
+
CreditCardIcon,
|
|
17
|
+
EllipsisVerticalIcon,
|
|
18
|
+
LogOutIcon, MoonIcon, ShieldCogIcon,
|
|
19
|
+
SunIcon
|
|
20
|
+
} from "lucide-react";
|
|
21
|
+
import React from "react";
|
|
22
|
+
import {Button} from "../../ui/button";
|
|
23
|
+
import {useThemePreferColorSchemeStore} from "../../theme/theme.store";
|
|
24
|
+
import {PreferColorSchemeEnum} from "../../theme/theme.enum";
|
|
25
|
+
import Link from "next/link";
|
|
26
|
+
import {LocalTime} from "../../components/local-time";
|
|
27
|
+
import {isAdminOrAbove} from "../../../infrastructure/utilities/permission.util";
|
|
28
|
+
|
|
29
|
+
export function HeaderTasksConnectedUser() {
|
|
30
|
+
const {colorScheme, toggleColorScheme} = useThemePreferColorSchemeStore()
|
|
31
|
+
const {user: authUser, currentOrganization} = useAuth();
|
|
32
|
+
const isAdmin = isAdminOrAbove(authUser, currentOrganization?.id);
|
|
33
|
+
const user = React.useMemo(() => {
|
|
34
|
+
const name = authUser?.username || authUser?.userData?.firstname || "Utilisateur";
|
|
35
|
+
const email = authUser?.email || "No email";
|
|
36
|
+
const avatarId = authUser?.avatar?.id;
|
|
37
|
+
let initials = "U";
|
|
38
|
+
if (authUser?.userData?.firstname && authUser?.userData?.lastname) {
|
|
39
|
+
initials = `${authUser.userData.firstname[0]}${authUser.userData.lastname[0]}`.toUpperCase();
|
|
40
|
+
} else if (authUser?.username) {
|
|
41
|
+
initials = authUser.username.substring(0, 2).toUpperCase();
|
|
42
|
+
} else if (authUser?.email) {
|
|
43
|
+
initials = authUser.email.substring(0, 2).toUpperCase();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
email,
|
|
49
|
+
avatarId,
|
|
50
|
+
initials,
|
|
51
|
+
};
|
|
52
|
+
}, [authUser]);
|
|
53
|
+
const {logout} = useAuth()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<DropdownMenu>
|
|
58
|
+
<DropdownMenuTrigger asChild>
|
|
59
|
+
<div
|
|
60
|
+
className="flex flex-row items-center p-2 rounded-md data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
61
|
+
>
|
|
62
|
+
<Avatar className="h-8 w-8 rounded-lg overflow-hidden">
|
|
63
|
+
{user.avatarId ? (
|
|
64
|
+
<StorageMedia id={user.avatarId} className="size-full object-cover"/>
|
|
65
|
+
) : (
|
|
66
|
+
<AvatarFallback className="rounded-lg">{user.initials}</AvatarFallback>
|
|
67
|
+
)}
|
|
68
|
+
</Avatar>
|
|
69
|
+
{/*<div className="grid flex-1 text-left text-sm leading-tight">*/}
|
|
70
|
+
{/* <span className="truncate font-medium">{user.name}</span>*/}
|
|
71
|
+
{/* <span className="truncate text-xs text-muted-foreground">{user.email}</span>*/}
|
|
72
|
+
{/*</div>*/}
|
|
73
|
+
<EllipsisVerticalIcon className="ml-auto size-4"/>
|
|
74
|
+
</div>
|
|
75
|
+
</DropdownMenuTrigger>
|
|
76
|
+
<DropdownMenuContent
|
|
77
|
+
className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
|
|
78
|
+
side={"bottom"}
|
|
79
|
+
align="end"
|
|
80
|
+
sideOffset={4}
|
|
81
|
+
>
|
|
82
|
+
<DropdownMenuLabel className="p-0 font-normal">
|
|
83
|
+
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
84
|
+
<Avatar className="h-8 w-8 rounded-full overflow-hidden">
|
|
85
|
+
{user.avatarId ? (
|
|
86
|
+
<StorageMedia id={user.avatarId} className="size-full object-cover"/>
|
|
87
|
+
) : (
|
|
88
|
+
<AvatarFallback className="rounded-lg">{user.initials}</AvatarFallback>
|
|
89
|
+
)}
|
|
90
|
+
</Avatar>
|
|
91
|
+
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
92
|
+
<span className="truncate font-medium">{user.name}</span>
|
|
93
|
+
<span className="truncate text-xs text-muted-foreground">
|
|
94
|
+
{user.email}
|
|
95
|
+
</span>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</DropdownMenuLabel>
|
|
99
|
+
<DropdownMenuSeparator/>
|
|
100
|
+
<DropdownMenuGroup>
|
|
101
|
+
<DropdownMenuItem asChild>
|
|
102
|
+
<Link href="/account" className="flex w-full items-center">
|
|
103
|
+
<CircleUserRoundIcon className="mr-2 h-4 w-4"/>
|
|
104
|
+
<span>Mon compte</span>
|
|
105
|
+
</Link>
|
|
106
|
+
</DropdownMenuItem>
|
|
107
|
+
<DropdownMenuItem asChild>
|
|
108
|
+
<Link href="/account/security" className="flex w-full items-center">
|
|
109
|
+
<ShieldCogIcon/>
|
|
110
|
+
Mot de passe
|
|
111
|
+
</Link>
|
|
112
|
+
</DropdownMenuItem>
|
|
113
|
+
<DropdownMenuItem asChild>
|
|
114
|
+
<Link href="/account/notifications" className="flex w-full items-center">
|
|
115
|
+
<BellIcon/>
|
|
116
|
+
Notifications
|
|
117
|
+
</Link>
|
|
118
|
+
</DropdownMenuItem>
|
|
119
|
+
</DropdownMenuGroup>
|
|
120
|
+
{isAdmin && (
|
|
121
|
+
<>
|
|
122
|
+
<DropdownMenuSeparator/>
|
|
123
|
+
<DropdownMenuGroup>
|
|
124
|
+
<DropdownMenuItem asChild>
|
|
125
|
+
<Link href="/organizations/settings" className="flex w-full items-center">
|
|
126
|
+
<CogIcon/>
|
|
127
|
+
Paramètres de l'organisation
|
|
128
|
+
</Link>
|
|
129
|
+
</DropdownMenuItem>
|
|
130
|
+
</DropdownMenuGroup>
|
|
131
|
+
</>
|
|
132
|
+
)}
|
|
133
|
+
<DropdownMenuSeparator/>
|
|
134
|
+
<DropdownMenuItem
|
|
135
|
+
onClick={() => toggleColorScheme(true)}>
|
|
136
|
+
{
|
|
137
|
+
(colorScheme !== PreferColorSchemeEnum.Light)
|
|
138
|
+
? <><SunIcon/> <span>Thème clair</span></>
|
|
139
|
+
: <><MoonIcon/> <span>Thème sombre</span></>
|
|
140
|
+
}
|
|
141
|
+
</DropdownMenuItem>
|
|
142
|
+
<DropdownMenuSeparator/>
|
|
143
|
+
<DropdownMenuItem onClick={logout} className="cursor-pointer">
|
|
144
|
+
<LogOutIcon/>
|
|
145
|
+
Se déconnecter
|
|
146
|
+
</DropdownMenuItem>
|
|
147
|
+
</DropdownMenuContent>
|
|
148
|
+
</DropdownMenu>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./view"
|
|
2
|
+
export * from "./view-wrapper"
|
|
3
|
+
export * from "./view-helmet"
|
|
4
|
+
export * from "./view-frame"
|
|
5
|
+
export * from "./view-status"
|
|
6
|
+
export * from "./main-wrapper"
|
|
7
|
+
export * from "./edge-section"
|
|
8
|
+
export * from "./header-menubar"
|
|
9
|
+
export * from "./header-modules-available"
|
|
10
|
+
export * from "./header-modules-recents"
|
|
11
|
+
export * from "./header-options"
|
|
12
|
+
export * from "./header-organization-select"
|
|
13
|
+
export * from "./header-routines"
|
|
14
|
+
export * from "./header-tasks-connected-user"
|
|
15
|
+
export * from "./module-item-link"
|
|
16
|
+
export * from "./dashboard-layout"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {cn} from "../../../infrastructure/utilities/utils";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export interface MainWrapperProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getMainWrapperSize(size?: MainWrapperProps['size']) {
|
|
11
|
+
switch (size) {
|
|
12
|
+
case 'sm':
|
|
13
|
+
return 'max-w-screen-sm';
|
|
14
|
+
case 'md':
|
|
15
|
+
return 'max-w-screen-md';
|
|
16
|
+
case 'lg':
|
|
17
|
+
return 'max-w-screen-lg';
|
|
18
|
+
}
|
|
19
|
+
return 'max-w-5xl'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function MainWrapper({children, className, size, ...props}: MainWrapperProps) {
|
|
23
|
+
let _size = getMainWrapperSize(size);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div {...props} className={cn(
|
|
27
|
+
"w-full max-w-5xl mx-auto flex flex-col gap-6",
|
|
28
|
+
_size,
|
|
29
|
+
className,
|
|
30
|
+
)}>
|
|
31
|
+
{children}
|
|
32
|
+
</div>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {ModuleDeclarationInterface} from "../../../domain/entities/module.interface";
|
|
2
|
+
import Link from "next/link";
|
|
3
|
+
import {LucideIcon} from "../../icons/lucide";
|
|
4
|
+
|
|
5
|
+
export interface ModuleListItemProps {
|
|
6
|
+
module: ModuleDeclarationInterface
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function ModuleItemLink({module}: ModuleListItemProps) {
|
|
10
|
+
return (
|
|
11
|
+
<Link
|
|
12
|
+
className={"col-span-1 flex flex-row gap-4 p-2 rounded-[inherit] cursor-pointer hover:bg-primary/20 hover:text-primary"}
|
|
13
|
+
href={module.uri}
|
|
14
|
+
>
|
|
15
|
+
<div className="flex pl-2 justify-center items-center">
|
|
16
|
+
<LucideIcon
|
|
17
|
+
name={module.icon || 'AppWindowMac'}
|
|
18
|
+
size={5}
|
|
19
|
+
className={"text-primary"}
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
<div className="flex flex-col gap-0 flex-auto w-full pr-6">
|
|
23
|
+
<div className="text-sm truncate">
|
|
24
|
+
{module.name}
|
|
25
|
+
</div>
|
|
26
|
+
<div className="text-xs truncate pr-6 text-ellipsis text-muted-foreground">
|
|
27
|
+
{module.description}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</Link>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../../infrastructure/utilities/utils"
|
|
4
|
+
import { Motion } from "../../../infrastructure/library/motion"
|
|
5
|
+
import { elasticEnter } from "../../../infrastructure/library/motion-utils"
|
|
6
|
+
|
|
7
|
+
export interface ViewFrameProps {
|
|
8
|
+
className?: string
|
|
9
|
+
children?: React.ReactNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ViewFrame({ className, children }: ViewFrameProps) {
|
|
13
|
+
return (
|
|
14
|
+
<Motion
|
|
15
|
+
as="main"
|
|
16
|
+
animation={elasticEnter()}
|
|
17
|
+
className={cn(
|
|
18
|
+
"flex-auto min-h-[100dvh-64px] w-full",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
</Motion>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {cn} from "../../../infrastructure/utilities/utils"
|
|
2
|
+
import React from "react"
|
|
3
|
+
import {HeaderRoutines} from "./header-routines"
|
|
4
|
+
import {HeaderOptions} from "./header-options"
|
|
5
|
+
import {HeaderOrganizationSelect} from "./header-organization-select"
|
|
6
|
+
import Link from "next/link"
|
|
7
|
+
import {ThemeLogo} from "../../system/logo.theme"
|
|
8
|
+
import {HeaderModulesAvailable} from "./header-modules-available"
|
|
9
|
+
import {HeaderModulesRecents} from "./header-modules-recents"
|
|
10
|
+
import {HeaderModulesStore} from "./header-modules-store"
|
|
11
|
+
import {Tooltip, TooltipContent, TooltipTrigger} from "../../ui/tooltip"
|
|
12
|
+
import {NavigationMenu} from "./header-menubar"
|
|
13
|
+
|
|
14
|
+
export interface ViewHelmetProps {
|
|
15
|
+
className?: string
|
|
16
|
+
fixed?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function ViewHelmet({className, fixed = true}: ViewHelmetProps) {
|
|
20
|
+
return (
|
|
21
|
+
<header className={cn(
|
|
22
|
+
"w-full h-16 flex items-start pt-0 gap-2 px-4",
|
|
23
|
+
fixed ? "relative md:fixed top-0 left-0 z-3 [&+*]:mt-0 sm:[&+*]:mt-16 sm:backdrop-blur-xl sm:mask-[linear-gradient(to_bottom,background_40%,transparent_100%)]" : "",
|
|
24
|
+
className
|
|
25
|
+
)}>
|
|
26
|
+
<div className="flex flex-row gap-4 item-center w-full h-12">
|
|
27
|
+
<div className="w-8 h-auto flex items-center justify-center">
|
|
28
|
+
<Tooltip>
|
|
29
|
+
<TooltipTrigger className={"text-primary"}>
|
|
30
|
+
<Link href={"/"} className="w-full h-full flex items-center justify-center">
|
|
31
|
+
<ThemeLogo color={"black"} onDark={"white"} variant={"square"}/>
|
|
32
|
+
</Link>
|
|
33
|
+
</TooltipTrigger>
|
|
34
|
+
<TooltipContent side={'bottom'} align={'start'}>
|
|
35
|
+
Tableau de bord
|
|
36
|
+
</TooltipContent>
|
|
37
|
+
</Tooltip>
|
|
38
|
+
</div>
|
|
39
|
+
<HeaderModulesAvailable/>
|
|
40
|
+
<HeaderModulesRecents/>
|
|
41
|
+
<HeaderModulesStore/>
|
|
42
|
+
<div className="flex flex-row items-center flex-auto">
|
|
43
|
+
<NavigationMenu size={'md'} />
|
|
44
|
+
</div>
|
|
45
|
+
<div className="flex flex-row items-center">
|
|
46
|
+
<HeaderOrganizationSelect/>
|
|
47
|
+
<HeaderRoutines/>
|
|
48
|
+
<HeaderOptions/>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</header>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {cn} from "../../../infrastructure/utilities/utils"
|
|
2
|
+
import {AppConfig} from "../../../domain/config/app.config"
|
|
3
|
+
import {EdgeSection} from "./edge-section"
|
|
4
|
+
|
|
5
|
+
export interface ViewStatusProps {
|
|
6
|
+
className?: string
|
|
7
|
+
children?: React.ReactNode
|
|
8
|
+
fixed?: boolean
|
|
9
|
+
breadcrumb?: React.ReactNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ViewStatus({className, children, fixed = true, breadcrumb}: ViewStatusProps) {
|
|
13
|
+
return (
|
|
14
|
+
<footer className={cn(
|
|
15
|
+
"",
|
|
16
|
+
className,
|
|
17
|
+
fixed
|
|
18
|
+
? "fixed bottom-0 left-0 w-screen flex flex-row items-center gap-4 px-4 pb-4 pt-6 z-3 backdrop-blur-xl mask-[linear-gradient(to_top,background_40%,transparent_100%)]"
|
|
19
|
+
: "flex flex-row items-center gap-4 p-4"
|
|
20
|
+
)}>
|
|
21
|
+
<EdgeSection className={"py-1 p-3"}>
|
|
22
|
+
{breadcrumb}
|
|
23
|
+
</EdgeSection>
|
|
24
|
+
<div className="flex-auto flex flex-row justify-end items-center">
|
|
25
|
+
{children}
|
|
26
|
+
</div>
|
|
27
|
+
<EdgeSection className="justify-end text-muted-foreground text-xs py-1 p-3">
|
|
28
|
+
© {AppConfig.COPYRIGHT_YEAR} {AppConfig.APP_NAME}
|
|
29
|
+
</EdgeSection>
|
|
30
|
+
</footer>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from "react"
|
|
4
|
+
|
|
5
|
+
export interface ViewWrapperProps {
|
|
6
|
+
children: React.ReactNode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function ViewWrapper({children}: ViewWrapperProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div className="relative max-w-screen w-full min-h-[100dvh-64px] flex flex-col md:flex-row gap-0 pb-24">
|
|
12
|
+
{children}
|
|
13
|
+
</div>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import type React from "react"
|
|
4
|
+
import {ViewWrapper} from "./view-wrapper"
|
|
5
|
+
import {ViewHelmet} from "./view-helmet"
|
|
6
|
+
import {ViewFrame} from "./view-frame"
|
|
7
|
+
import {ViewStatus} from "./view-status"
|
|
8
|
+
|
|
9
|
+
export interface ScreenViewProps {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const View: React.FC<ScreenViewProps> & {
|
|
14
|
+
Wrapper: typeof ViewWrapper
|
|
15
|
+
Helmet: typeof ViewHelmet
|
|
16
|
+
Frame: typeof ViewFrame
|
|
17
|
+
Status: typeof ViewStatus
|
|
18
|
+
} = Object.assign(
|
|
19
|
+
function View({children}: ScreenViewProps) {
|
|
20
|
+
return (
|
|
21
|
+
<div className="relative max-w-screen w-full min-h-screen h-full">
|
|
22
|
+
{/* back */}
|
|
23
|
+
<div className="fixed inset-0 z-0 overflow-hidden pointer-events-none">
|
|
24
|
+
<div className="view-component-effects effect-1" />
|
|
25
|
+
<div className="view-component-effects effect-2" />
|
|
26
|
+
<div className="view-component-effects effect-3" />
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
{/* fore */}
|
|
30
|
+
<div className="static max-w-screen w-full min-h-screen h-full flex flex-col gap-0 z-1">
|
|
31
|
+
{children}
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
Wrapper: ViewWrapper,
|
|
38
|
+
Helmet: ViewHelmet,
|
|
39
|
+
Frame: ViewFrame,
|
|
40
|
+
Status: ViewStatus,
|
|
41
|
+
}
|
|
42
|
+
)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
5
|
+
import { Check, ChevronDown } from "lucide-react"
|
|
6
|
+
import { cn } from "../../infrastructure/utilities/utils"
|
|
7
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
|
8
|
+
|
|
9
|
+
// --- Architecture: Primitives (Unstyled but behaving) ---
|
|
10
|
+
// We are using Radix UI Accordion and Checkbox primitives directly.
|
|
11
|
+
// This component acts as a "Component" layer in the architecture:
|
|
12
|
+
// - Wraps primitives with styling
|
|
13
|
+
// - Supports controlled/uncontrolled usage
|
|
14
|
+
// - Uses data-attributes for state and slots for targeting
|
|
15
|
+
|
|
16
|
+
// --- Context ---
|
|
17
|
+
// We use a context to share selection state between the root and items/checkboxes
|
|
18
|
+
// This allows for the Compound Component pattern.
|
|
19
|
+
interface AccordionMultiselectContextValue {
|
|
20
|
+
selectedValues: string[]
|
|
21
|
+
onSelectionChange: (value: string, checked: boolean) => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const AccordionMultiselectContext = React.createContext<AccordionMultiselectContextValue | null>(null)
|
|
25
|
+
|
|
26
|
+
function useAccordionMultiselect() {
|
|
27
|
+
const context = React.useContext(AccordionMultiselectContext)
|
|
28
|
+
if (!context) {
|
|
29
|
+
throw new Error("AccordionMultiselect subcomponents must be used within AccordionMultiselect")
|
|
30
|
+
}
|
|
31
|
+
return context
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// --- Components ---
|
|
35
|
+
|
|
36
|
+
// We can't directly extend AccordionPrimitive.Root because it has specific props that might conflict or be typed in a way TS doesn't like for intersection
|
|
37
|
+
// Instead, we'll define our props and intersect with the primitive's props, excluding what we override/don't need if necessary
|
|
38
|
+
type AccordionRootProps = React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Root>
|
|
39
|
+
|
|
40
|
+
interface AccordionMultiselectProps
|
|
41
|
+
extends Omit<AccordionRootProps, "type" | "value" | "defaultValue" | "onValueChange"> {
|
|
42
|
+
value?: string[]
|
|
43
|
+
onValueChange?: (value: string[]) => void
|
|
44
|
+
defaultValue?: string[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function AccordionMultiselect({
|
|
48
|
+
value: controlledValue,
|
|
49
|
+
onValueChange,
|
|
50
|
+
defaultValue = [],
|
|
51
|
+
className,
|
|
52
|
+
children,
|
|
53
|
+
...props
|
|
54
|
+
}: AccordionMultiselectProps) {
|
|
55
|
+
// Controlled/Uncontrolled pattern
|
|
56
|
+
const [internalValue, setInternalValue] = React.useState<string[]>(defaultValue)
|
|
57
|
+
const isControlled = controlledValue !== undefined
|
|
58
|
+
const selectedValues = isControlled ? controlledValue : internalValue
|
|
59
|
+
|
|
60
|
+
const handleSelectionChange = React.useCallback(
|
|
61
|
+
(value: string, checked: boolean) => {
|
|
62
|
+
let newValues: string[]
|
|
63
|
+
if (checked) {
|
|
64
|
+
newValues = [...selectedValues, value]
|
|
65
|
+
} else {
|
|
66
|
+
newValues = selectedValues.filter(id => id !== value)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!isControlled) {
|
|
70
|
+
setInternalValue(newValues)
|
|
71
|
+
}
|
|
72
|
+
onValueChange?.(newValues)
|
|
73
|
+
},
|
|
74
|
+
[selectedValues, isControlled, onValueChange],
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<AccordionMultiselectContext.Provider value={{ selectedValues, onSelectionChange: handleSelectionChange }}>
|
|
79
|
+
<AccordionPrimitive.Root
|
|
80
|
+
type="multiple"
|
|
81
|
+
data-slot="accordion-multiselect-root"
|
|
82
|
+
className={cn("w-full space-y-4", className)}
|
|
83
|
+
{...props}
|
|
84
|
+
>
|
|
85
|
+
{children}
|
|
86
|
+
</AccordionPrimitive.Root>
|
|
87
|
+
</AccordionMultiselectContext.Provider>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function AccordionMultiselectItem({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>) {
|
|
95
|
+
return (
|
|
96
|
+
<AccordionPrimitive.Item
|
|
97
|
+
data-slot="accordion-multiselect-item"
|
|
98
|
+
className={cn("border-b-0", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function AccordionMultiselectTrigger({
|
|
105
|
+
className,
|
|
106
|
+
children,
|
|
107
|
+
...props
|
|
108
|
+
}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>) {
|
|
109
|
+
return (
|
|
110
|
+
<AccordionPrimitive.Header className="flex">
|
|
111
|
+
<AccordionPrimitive.Trigger
|
|
112
|
+
data-slot="accordion-multiselect-trigger"
|
|
113
|
+
className={cn(
|
|
114
|
+
"flex flex-1 items-center justify-between py-2 font-semibold text-base transition-all hover:no-underline [&[data-state=open]>svg]:rotate-180 cursor-pointer",
|
|
115
|
+
className,
|
|
116
|
+
)}
|
|
117
|
+
{...props}
|
|
118
|
+
>
|
|
119
|
+
{children}
|
|
120
|
+
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200 text-muted-foreground" />
|
|
121
|
+
</AccordionPrimitive.Trigger>
|
|
122
|
+
</AccordionPrimitive.Header>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function AccordionMultiselectContent({
|
|
127
|
+
className,
|
|
128
|
+
children,
|
|
129
|
+
...props
|
|
130
|
+
}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>) {
|
|
131
|
+
return (
|
|
132
|
+
<AccordionPrimitive.Content
|
|
133
|
+
data-slot="accordion-multiselect-content"
|
|
134
|
+
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
135
|
+
{...props}
|
|
136
|
+
>
|
|
137
|
+
<div className={cn("pt-2 pb-4 flex flex-col gap-2", className)}>{children}</div>
|
|
138
|
+
</AccordionPrimitive.Content>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// --- Sub-components for Item Options ---
|
|
143
|
+
|
|
144
|
+
interface AccordionMultiselectOptionProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
145
|
+
value: string
|
|
146
|
+
showCheckbox?: boolean
|
|
147
|
+
children: React.ReactNode
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function AccordionMultiselectOption({
|
|
151
|
+
value,
|
|
152
|
+
showCheckbox = false,
|
|
153
|
+
className,
|
|
154
|
+
onClick,
|
|
155
|
+
children,
|
|
156
|
+
...props
|
|
157
|
+
}: AccordionMultiselectOptionProps) {
|
|
158
|
+
const { selectedValues, onSelectionChange } = useAccordionMultiselect()
|
|
159
|
+
const isSelected = selectedValues.includes(value)
|
|
160
|
+
|
|
161
|
+
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
162
|
+
onSelectionChange(value, !isSelected)
|
|
163
|
+
onClick?.(e)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<div
|
|
168
|
+
data-slot="accordion-multiselect-option"
|
|
169
|
+
data-state={isSelected ? "checked" : "unchecked"}
|
|
170
|
+
className={cn(
|
|
171
|
+
"flex items-start space-x-3 rounded-md group cursor-pointer transition-all border border-transparent",
|
|
172
|
+
"hover:border-foreground/10 data-[state=checked]:bg-foreground/6",
|
|
173
|
+
className,
|
|
174
|
+
)}
|
|
175
|
+
onClick={handleClick}
|
|
176
|
+
{...props}
|
|
177
|
+
>
|
|
178
|
+
{showCheckbox && (
|
|
179
|
+
<div className="flex items-center h-5 mt-1">
|
|
180
|
+
<CheckboxPrimitive.Root
|
|
181
|
+
id={value}
|
|
182
|
+
checked={isSelected}
|
|
183
|
+
onCheckedChange={checked => onSelectionChange(value, checked as boolean)}
|
|
184
|
+
onClick={e => e.stopPropagation()}
|
|
185
|
+
className={cn(
|
|
186
|
+
"peer h-4 w-4 shrink-0 rounded-[3px] border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
187
|
+
)}
|
|
188
|
+
>
|
|
189
|
+
<CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
|
|
190
|
+
<Check className="h-4 w-4" />
|
|
191
|
+
</CheckboxPrimitive.Indicator>
|
|
192
|
+
</CheckboxPrimitive.Root>
|
|
193
|
+
</div>
|
|
194
|
+
)}
|
|
195
|
+
<div className="flex-1">{children}</div>
|
|
196
|
+
</div>
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export {
|
|
201
|
+
AccordionMultiselect,
|
|
202
|
+
AccordionMultiselectItem,
|
|
203
|
+
AccordionMultiselectTrigger,
|
|
204
|
+
AccordionMultiselectContent,
|
|
205
|
+
AccordionMultiselectOption,
|
|
206
|
+
}
|