diff --git a/package-lock.json b/package-lock.json index a47eedc..d0beebc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "name": "aio-shadcn-vite", "version": "0.0.0", "dependencies": { - "@internationalized/date": "^3.12.1", "@tanstack/vue-table": "^8.21.3", "@vee-validate/zod": "^4.15.1", "@vueuse/components": "^12.5.0", @@ -29,7 +28,7 @@ "qr-scanner": "^1.4.2", "qrcode": "^1.5.4", "radix-vue": "^1.9.13", - "reka-ui": "^2.9.7", + "reka-ui": "^2.6.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "unique-names-generator": "^4.7.1", @@ -3949,9 +3948,9 @@ } }, "node_modules/@internationalized/date": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.1.tgz", - "integrity": "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.7.0.tgz", + "integrity": "sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==", "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" @@ -7055,9 +7054,9 @@ } }, "node_modules/defu": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", - "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "license": "MIT" }, "node_modules/detect-libc": { @@ -12226,9 +12225,9 @@ } }, "node_modules/reka-ui": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.9.7.tgz", - "integrity": "sha512-aX7foYYR20v4+majO58OJJdBNfLMm0eJb448l9N4JVy8JB7GXOr4H/S4a+J1pkcoxZH8Cb7YHpJ855+miAm7sA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.6.0.tgz", + "integrity": "sha512-NrGMKrABD97l890mFS3TNUzB0BLUfbL3hh0NjcJRIUSUljb288bx3Mzo31nOyUcdiiW0HqFGXJwyCBh9cWgb0w==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.13", @@ -12236,62 +12235,26 @@ "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", - "@vueuse/core": "^14.1.0", - "@vueuse/shared": "^14.1.0", + "@vueuse/core": "^12.5.0", + "@vueuse/shared": "^12.5.0", "aria-hidden": "^1.2.4", - "defu": "^6.1.5", + "defu": "^6.1.4", "ohash": "^2.0.11" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/zernonia" - }, "peerDependencies": { - "vue": ">= 3.4.0" - } - }, - "node_modules/reka-ui/node_modules/@types/web-bluetooth": { - "version": "0.0.21", - "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", - "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", - "license": "MIT" - }, - "node_modules/reka-ui/node_modules/@vueuse/core": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.3.0.tgz", - "integrity": "sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==", - "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.21", - "@vueuse/metadata": "14.3.0", - "@vueuse/shared": "14.3.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "vue": "^3.5.0" - } - }, - "node_modules/reka-ui/node_modules/@vueuse/metadata": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", - "integrity": "sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" + "vue": ">= 3.2.0" } }, "node_modules/reka-ui/node_modules/@vueuse/shared": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.3.0.tgz", - "integrity": "sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==", + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, "funding": { "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "vue": "^3.5.0" } }, "node_modules/require-directory": { diff --git a/package.json b/package.json index 36cf2cf..2c2f2dd 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "make": "electron-forge make" }, "dependencies": { - "@internationalized/date": "^3.12.1", "@tanstack/vue-table": "^8.21.3", "@vee-validate/zod": "^4.15.1", "@vueuse/components": "^12.5.0", @@ -64,7 +63,7 @@ "qr-scanner": "^1.4.2", "qrcode": "^1.5.4", "radix-vue": "^1.9.13", - "reka-ui": "^2.9.7", + "reka-ui": "^2.6.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "unique-names-generator": "^4.7.1", diff --git a/src/components/ui/calendar/Calendar.vue b/src/components/ui/calendar/Calendar.vue deleted file mode 100644 index d112cf3..0000000 --- a/src/components/ui/calendar/Calendar.vue +++ /dev/null @@ -1,58 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarCell.vue b/src/components/ui/calendar/CalendarCell.vue deleted file mode 100644 index 53ff2d9..0000000 --- a/src/components/ui/calendar/CalendarCell.vue +++ /dev/null @@ -1,22 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarCellTrigger.vue b/src/components/ui/calendar/CalendarCellTrigger.vue deleted file mode 100644 index a4beb75..0000000 --- a/src/components/ui/calendar/CalendarCellTrigger.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarGrid.vue b/src/components/ui/calendar/CalendarGrid.vue deleted file mode 100644 index 5f52519..0000000 --- a/src/components/ui/calendar/CalendarGrid.vue +++ /dev/null @@ -1,22 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarGridBody.vue b/src/components/ui/calendar/CalendarGridBody.vue deleted file mode 100644 index 4fe36d7..0000000 --- a/src/components/ui/calendar/CalendarGridBody.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarGridHead.vue b/src/components/ui/calendar/CalendarGridHead.vue deleted file mode 100644 index 376d70b..0000000 --- a/src/components/ui/calendar/CalendarGridHead.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarGridRow.vue b/src/components/ui/calendar/CalendarGridRow.vue deleted file mode 100644 index ae99082..0000000 --- a/src/components/ui/calendar/CalendarGridRow.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarHeadCell.vue b/src/components/ui/calendar/CalendarHeadCell.vue deleted file mode 100644 index 911f909..0000000 --- a/src/components/ui/calendar/CalendarHeadCell.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarHeader.vue b/src/components/ui/calendar/CalendarHeader.vue deleted file mode 100644 index 706f78b..0000000 --- a/src/components/ui/calendar/CalendarHeader.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarHeading.vue b/src/components/ui/calendar/CalendarHeading.vue deleted file mode 100644 index 3b84ee8..0000000 --- a/src/components/ui/calendar/CalendarHeading.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarNextButton.vue b/src/components/ui/calendar/CalendarNextButton.vue deleted file mode 100644 index ae8861c..0000000 --- a/src/components/ui/calendar/CalendarNextButton.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/src/components/ui/calendar/CalendarPrevButton.vue b/src/components/ui/calendar/CalendarPrevButton.vue deleted file mode 100644 index 43e32a0..0000000 --- a/src/components/ui/calendar/CalendarPrevButton.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/src/components/ui/calendar/index.ts b/src/components/ui/calendar/index.ts deleted file mode 100644 index f222de0..0000000 --- a/src/components/ui/calendar/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { default as Calendar } from "./Calendar.vue" -export { default as CalendarCell } from "./CalendarCell.vue" -export { default as CalendarCellTrigger } from "./CalendarCellTrigger.vue" -export { default as CalendarGrid } from "./CalendarGrid.vue" -export { default as CalendarGridBody } from "./CalendarGridBody.vue" -export { default as CalendarGridHead } from "./CalendarGridHead.vue" -export { default as CalendarGridRow } from "./CalendarGridRow.vue" -export { default as CalendarHeadCell } from "./CalendarHeadCell.vue" -export { default as CalendarHeader } from "./CalendarHeader.vue" -export { default as CalendarHeading } from "./CalendarHeading.vue" -export { default as CalendarNextButton } from "./CalendarNextButton.vue" -export { default as CalendarPrevButton } from "./CalendarPrevButton.vue" diff --git a/src/modules/activities/components/CreateEventDialog.vue b/src/modules/activities/components/CreateEventDialog.vue index 1855049..2a9861a 100644 --- a/src/modules/activities/components/CreateEventDialog.vue +++ b/src/modules/activities/components/CreateEventDialog.vue @@ -24,6 +24,7 @@ import { Input } from '@/components/ui/input' import { Textarea } from '@/components/ui/textarea' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' +import { Separator } from '@/components/ui/separator' import { ScrollArea } from '@/components/ui/scroll-area' import { Select, @@ -32,12 +33,15 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select' -import { Calendar, Loader2, MapPin } from 'lucide-vue-next' +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from '@/components/ui/collapsible' +import { Calendar, Loader2, ChevronDown, MapPin } from 'lucide-vue-next' import { toastService } from '@/core/services/ToastService' import { injectService, SERVICE_TOKENS } from '@/core/di-container' import ImageUpload from '@/modules/base/components/ImageUpload.vue' -import DatePicker from '@/modules/base/components/DatePicker.vue' -import TimePicker from '@/modules/base/components/TimePicker.vue' import type { ImageUploadService, UploadedImage } from '@/modules/base/services/ImageUploadService' import type { TicketApiService } from '../services/TicketApiService' import type { CreateEventRequest } from '../types/ticket' @@ -56,45 +60,18 @@ const emit = defineEmits<{ const { t } = useI18n() -// Fold a date input ("YYYY-MM-DD") and an optional time input ("HH:MM") -// into the events-extension wire format: date-only when no time given, -// ISO 8601 datetime otherwise. The publisher switches NIP-52 kinds on -// the "T" delimiter. Hoisted above the schema so the validation refine -// can reuse it. -function foldDateTime(date: string, time: string): string { - if (!date) return '' - return time ? `${date}T${time}` : date -} - -const formSchema = toTypedSchema( - z - .object({ - name: z.string().min(1, "Title is required").max(200, "Title too long"), - info: z.string().max(2000, "Description too long").optional().default(''), - event_start_date: z.string().min(1, "Start date is required"), - event_start_time: z.string().optional().default(''), - event_end_date: z.string().optional().default(''), - event_end_time: z.string().optional().default(''), - location: z.string().max(500).optional().default(''), - currency: z.string().default("sat"), - amount_tickets: z.number().min(0).max(100000).default(0), - price_per_ticket: z.number().min(0).default(0), - }) - .superRefine((v, ctx) => { - // End must not precede start. Compare on the folded date+time - // string so equal-date / later-time is enforced too. - if (!v.event_end_date) return - const start = foldDateTime(v.event_start_date, v.event_start_time) - const end = foldDateTime(v.event_end_date, v.event_end_time) - if (start && end && end < start) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ['event_end_date'], - message: 'End must be on or after start', - }) - } - }) -) +const formSchema = toTypedSchema(z.object({ + name: z.string().min(1, "Title is required").max(200, "Title too long"), + info: z.string().max(2000, "Description too long").optional().default(''), + event_start_date: z.string().min(1, "Start date is required"), + event_start_time: z.string().optional().default(''), + event_end_date: z.string().optional().default(''), + event_end_time: z.string().optional().default(''), + location: z.string().max(500).optional().default(''), + currency: z.string().default("sat"), + amount_tickets: z.number().min(0).max(100000).default(0), + price_per_ticket: z.number().min(0).default(0), +})) const form = useForm({ validationSchema: formSchema, @@ -117,21 +94,14 @@ interface BannerImage extends UploadedImage { } const bannerImages = ref([]) -// Auto-mirror end date to start: when the user picks a start date, -// surface that same date in the end-date picker so a one-day event -// requires no extra clicks. Don't overwrite an end date the user -// already set *after* the start — only fill when empty or when the -// existing end has fallen behind the new start. -watch( - () => form.values.event_start_date, - (start, prev) => { - if (!start) return - const end = form.values.event_end_date - if (!end || end < start || end === prev) { - form.setFieldValue('event_end_date', start) - } - } -) +// Fold a date input ("YYYY-MM-DD") and an optional time input ("HH:MM") +// into the events-extension wire format: date-only when no time given, +// ISO 8601 datetime otherwise. The publisher switches NIP-52 kinds on +// the "T" delimiter. +function foldDateTime(date: string, time: string): string { + if (!date) return '' + return time ? `${date}T${time}` : date +} const paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE) const ticketApi = injectService(SERVICE_TOKENS.TICKET_API) as TicketApiService | null @@ -140,6 +110,7 @@ const imageService = injectService(SERVICE_TOKENS.IMAGE_UPLO const availableCurrencies = ref(['sat']) const loadingCurrencies = ref(false) const selectedCategories = ref([]) +const showMoreOptions = ref(false) watch(() => props.open, async (isOpen) => { if (isOpen && ticketApi && !loadingCurrencies.value) { @@ -154,6 +125,7 @@ watch(() => props.open, async (isOpen) => { } if (!isOpen) { selectedCategories.value = [] + showMoreOptions.value = false } }) @@ -268,67 +240,21 @@ const handleOpenChange = (open: boolean) => {
- + Start date * - + - + Start time - - - - - -
- - -
- - - End date - - - - - - - - - - - End time - (optional) - - - + @@ -445,6 +371,42 @@ const handleOpenChange = (open: boolean) => {
+ + + + + + + + +
+ + + End date + + + + Defaults to start date + + + + + + + End time + + + + + + +
+
+
+