@devvistatech/devvista-kit 0.0.10 → 0.0.13
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/CHANGELOG.md +12 -12
- package/LICENSE +6 -6
- package/README.md +55 -15
- package/app/ClientLayout.tsx +66 -0
- package/app/about/page.tsx +61 -298
- package/app/adRequest/page.tsx +625 -549
- package/app/admin-profile/page.tsx +123 -0
- package/app/analytics/page.tsx +382 -346
- package/app/api/about/route.ts +290 -306
- package/app/api/adRequest/route.ts +547 -567
- package/app/api/analytics/[reportType]/route.ts +274 -337
- package/app/api/bio/route.ts +297 -313
- package/app/api/blog/route.ts +288 -306
- package/app/api/chat/route.ts +14 -14
- package/app/api/contact/route.ts +409 -409
- package/app/api/contacts/route.ts +179 -224
- package/app/api/files/route.ts +415 -429
- package/app/api/gallery-data/route.ts +727 -735
- package/app/api/schedule/route.ts +439 -455
- package/app/api/signup/route.ts +129 -0
- package/app/api/sync-user/route.ts +306 -132
- package/app/api/trial-request/route.ts +297 -297
- package/app/api/verify-admin/route.ts +46 -0
- package/app/blog/[id]/page.tsx +307 -288
- package/app/blog/page.tsx +249 -216
- package/app/contact/page.tsx +284 -284
- package/app/faq/page.tsx +191 -191
- package/app/favicon.ico +0 -0
- package/app/gallery/page.tsx +336 -315
- package/app/globals.css +58 -58
- package/app/layout.tsx +59 -110
- package/app/not-found.tsx +20 -20
- package/app/page.tsx +47 -338
- package/app/products/constants/product.ts +27 -0
- package/app/products/page.tsx +296 -0
- package/app/products/productOne/page.tsx +266 -0
- package/app/products/productTwo/page.tsx +272 -0
- package/app/schedule/page.tsx +698 -660
- package/bin/init.js +207 -219
- package/components/addOns/functional/CalendlyWidget.tsx +107 -107
- package/components/addOns/functional/ClassList.tsx +149 -145
- package/components/addOns/functional/ClassPopup.tsx +398 -398
- package/components/addOns/functional/ContactForm.tsx +284 -284
- package/components/addOns/functional/NewUserAnalytics.tsx +100 -100
- package/components/addOns/functional/ProductList.tsx +1027 -0
- package/components/addOns/functional/aboutSections/AboutSection.tsx +581 -544
- package/components/addOns/functional/aboutSections/constants/aboutSection.ts +70 -65
- package/components/addOns/functional/banner/Banner.tsx +150 -0
- package/components/addOns/functional/banner/BannerDashboard.tsx +283 -0
- package/components/addOns/functional/bioSections/BioEditor.tsx +471 -0
- package/components/addOns/functional/bioSections/constants/bioEditor.ts +36 -0
- package/components/addOns/functional/blogSections/BlogDashboard.tsx +184 -184
- package/components/addOns/functional/blogSections/BlogFormPopUp.tsx +555 -554
- package/components/addOns/functional/blogSections/BlogList.tsx +148 -148
- package/components/addOns/functional/blogSections/BlogSidebar.tsx +58 -58
- package/components/addOns/functional/blogSections/constants/blogDashboard.ts +28 -28
- package/components/addOns/functional/blogSections/constants/blogFormPopUp.ts +97 -97
- package/components/addOns/functional/blogSections/constants/blogList.ts +22 -22
- package/components/addOns/functional/blogSections/constants/blogSidebar.ts +15 -15
- package/components/addOns/functional/{ImageDescCarousel.tsx → carousels/ImageDescCarousel.tsx} +839 -730
- package/components/addOns/functional/carousels/ProductDescCarousel.tsx +1129 -0
- package/components/addOns/functional/{ScheduleCarousel.tsx → carousels/ScheduleCarousel.tsx} +231 -171
- package/components/addOns/functional/carousels/constants.ts/productDescCarousel.ts +197 -0
- package/components/addOns/functional/carousels/constants.ts/scheduleCarousel.ts +20 -0
- package/components/addOns/functional/contactsDashboard/ContactsDashboard.tsx +366 -366
- package/components/addOns/functional/contactsDashboard/constants/contactsDashboard.ts +70 -70
- package/components/addOns/functional/fileUploaders/FileUploader.tsx +437 -0
- package/components/addOns/functional/fileUploaders/constants/fileUploader.ts +45 -0
- package/components/addOns/functional/galleries/GalleryComplex.tsx +1037 -836
- package/components/addOns/functional/galleries/GallerySimple.tsx +537 -509
- package/components/addOns/functional/galleries/ThreeSetGallery.tsx +260 -0
- package/components/addOns/functional/galleries/constants/galleryComplex.ts +106 -106
- package/components/addOns/functional/galleries/constants/gallerySimple.ts +76 -76
- package/components/addOns/functional/schedules/ScheduleGridOne.tsx +276 -262
- package/components/addOns/functional/schedules/ScheduleGridTwo.tsx +299 -294
- package/components/addOns/functional/schedules/ScheduleGridTwoBasic.tsx +293 -288
- package/components/addOns/functional/schedules/SchedulerForm.tsx +428 -428
- package/components/addOns/functional/schedules/constants/ScheduleGridTwo.ts +40 -40
- package/components/addOns/functional/schedules/constants/ScheduleGridTwoBasic.ts +40 -40
- package/components/addOns/functional/schedules/constants/SchedulerForm.ts +65 -65
- package/components/addOns/functional/schedules/constants/scheduleGridOne.ts +54 -54
- package/components/addOns/non-functional/AnnouncementBanner.tsx +46 -46
- package/components/addOns/non-functional/IconBubble.tsx +49 -49
- package/components/addOns/non-functional/SampleCarousel.tsx +204 -204
- package/components/addOns/non-functional/Testimonials.tsx +334 -334
- package/components/addOns/non-functional/ThreeSetGallery.tsx +63 -63
- package/components/addOns/non-functional/aboutSections/AboutSection.tsx +62 -62
- package/components/addOns/non-functional/aboutSections/constants/aboutSection.ts +24 -24
- package/components/addOns/non-functional/featureSections/FeaturesSection.tsx +74 -0
- package/components/addOns/non-functional/featureSections/constants/featuresSection.ts +30 -0
- package/components/addOns/non-functional/{Heros/HeroSection.tsx → heros/HomeHero.tsx} +144 -142
- package/components/addOns/non-functional/heros/ProductHero.tsx +111 -0
- package/components/addOns/non-functional/heros/constants/hero.ts +62 -0
- package/components/addOns/non-functional/imageCarousels/ProductSlider.tsx +117 -117
- package/components/addOns/non-functional/imageCarousels/ProgramCarousel.tsx +232 -232
- package/components/addOns/non-functional/imageCarousels/constants/programCarousel.ts +39 -39
- package/components/addOns/non-functional/imageCarousels/constants/programSlider.ts +36 -36
- package/components/addOns/non-functional/spinner.tsx +21 -21
- package/components/footers/footer.tsx +416 -453
- package/components/navBars/navbar.tsx +310 -310
- package/components/other/accordion.tsx +58 -58
- package/components/other/admin-menu.tsx +68 -68
- package/components/other/alert-dialog.tsx +141 -141
- package/components/other/alert.tsx +59 -59
- package/components/other/aspect-ratio.tsx +7 -7
- package/components/other/avatar.tsx +50 -50
- package/components/other/badge.tsx +36 -36
- package/components/other/breadcrumb.tsx +115 -115
- package/components/other/button.tsx +738 -738
- package/components/other/calendar.tsx +66 -66
- package/components/other/card.tsx +86 -86
- package/components/other/carousel.tsx +274 -274
- package/components/other/chart.tsx +363 -363
- package/components/other/checkbox.tsx +30 -30
- package/components/other/collapsible.tsx +11 -11
- package/components/other/command.tsx +155 -155
- package/components/other/context-menu.tsx +200 -200
- package/components/other/dialog.tsx +122 -122
- package/components/other/drawer.tsx +118 -118
- package/components/other/dropdown-menu.tsx +200 -200
- package/components/other/form.tsx +179 -179
- package/components/other/hover-card.tsx +29 -29
- package/components/other/input-otp.tsx +71 -71
- package/components/other/input.tsx +25 -25
- package/components/other/label.tsx +26 -26
- package/components/other/menubar.tsx +236 -236
- package/components/other/mobile-icon.tsx +21 -21
- package/components/other/navigation-menu.tsx +128 -128
- package/components/other/pagination.tsx +117 -117
- package/components/other/popover.tsx +31 -31
- package/components/other/progress.tsx +28 -28
- package/components/other/radio-group.tsx +44 -44
- package/components/other/resizable.tsx +45 -45
- package/components/other/scroll-area.tsx +48 -48
- package/components/other/select.tsx +160 -160
- package/components/other/separator.tsx +31 -31
- package/components/other/sheet.tsx +140 -140
- package/components/other/skeleton.tsx +15 -15
- package/components/other/slider.tsx +28 -28
- package/components/other/social-icons.tsx +39 -39
- package/components/other/sonner.tsx +31 -31
- package/components/other/switch.tsx +29 -29
- package/components/other/table.tsx +117 -117
- package/components/other/tabs.tsx +55 -55
- package/components/other/textarea.tsx +24 -24
- package/components/other/toast.tsx +122 -122
- package/components/other/toaster.tsx +35 -35
- package/components/other/toggle-group.tsx +61 -61
- package/components/other/toggle.tsx +45 -45
- package/components/other/tooltip.tsx +30 -30
- package/components/theme-provider.tsx +8 -8
- package/hooks/use-toast.ts +188 -188
- package/lib/auth/auth-context.tsx +225 -0
- package/lib/auth/auth-utils.tsx +30 -0
- package/lib/constants/about.ts +34 -34
- package/lib/constants/adRequest.ts +256 -113
- package/lib/constants/admin-profile.ts +12 -0
- package/lib/constants/contact.ts +40 -40
- package/lib/constants/faq.ts +34 -34
- package/lib/constants/gallery.ts +42 -42
- package/lib/constants/page.ts +69 -69
- package/lib/constants/schedule.ts +71 -71
- package/lib/google/google-analytics-tracking.tsx +44 -0
- package/lib/{google-analytics.tsx → google/google-analytics.tsx} +97 -97
- package/lib/types.ts +235 -0
- package/lib/utils/compressImage.tsx +32 -0
- package/middleware.ts +46 -42
- package/netlify.toml +5 -5
- package/next.config.js +10 -10
- package/package.json +117 -116
- package/public/images/test.png +0 -0
- package/tailwind.config.ts +89 -89
- package/tsconfig.json +23 -23
- package/components/addOns/functional/BioEditor.tsx +0 -447
- package/components/addOns/functional/FileUploader.tsx +0 -295
- package/components/addOns/non-functional/FeaturesSection.tsx +0 -63
- package/components/types.ts +0 -50
- package/dist/.next/types/app/api/about/route.js +0 -52
- package/dist/.next/types/app/api/blog/route.js +0 -52
- package/dist/.next/types/app/api/files/route.js +0 -52
- package/dist/.next/types/app/api/schedule/route.js +0 -52
- package/dist/.next/types/app/api/sync-user/route.js +0 -52
- package/dist/.next/types/app/layout.js +0 -22
- package/dist/.next/types/app/page.js +0 -22
- package/dist/app/about/page.jsx +0 -258
- package/dist/app/adRequest/page.jsx +0 -531
- package/dist/app/analytics/page.jsx +0 -298
- package/dist/app/api/about/route.js +0 -285
- package/dist/app/api/adRequest/route.js +0 -440
- package/dist/app/api/analytics/[reportType]/route.js +0 -357
- package/dist/app/api/bio/route.js +0 -293
- package/dist/app/api/blog/route.js +0 -366
- package/dist/app/api/chat/route.js +0 -58
- package/dist/app/api/contact/route.js +0 -163
- package/dist/app/api/contacts/route.js +0 -234
- package/dist/app/api/files/route.js +0 -444
- package/dist/app/api/gallery-data/route.js +0 -719
- package/dist/app/api/schedule/route.js +0 -461
- package/dist/app/api/sync-user/route.js +0 -186
- package/dist/app/api/trial-request/route.js +0 -165
- package/dist/app/blog/[id]/page.jsx +0 -312
- package/dist/app/blog/page.jsx +0 -210
- package/dist/app/constants/about.js +0 -32
- package/dist/app/constants/adRequest.js +0 -113
- package/dist/app/constants/contact.js +0 -40
- package/dist/app/constants/faq.js +0 -36
- package/dist/app/constants/gallery.js +0 -42
- package/dist/app/constants/page.js +0 -69
- package/dist/app/constants/schedule.js +0 -71
- package/dist/app/contact/page.jsx +0 -119
- package/dist/app/faq/page.jsx +0 -97
- package/dist/app/gallery/page.jsx +0 -281
- package/dist/app/layout.jsx +0 -45
- package/dist/app/not-found.jsx +0 -14
- package/dist/app/page.jsx +0 -324
- package/dist/app/schedule/page.jsx +0 -500
- package/dist/components/addOns/functional/BioEditor.jsx +0 -187
- package/dist/components/addOns/functional/CalendlyWidget.jsx +0 -61
- package/dist/components/addOns/functional/ClassList.jsx +0 -158
- package/dist/components/addOns/functional/ClassPopup.jsx +0 -300
- package/dist/components/addOns/functional/ContactForm.jsx +0 -219
- package/dist/components/addOns/functional/FileUploader.jsx +0 -222
- package/dist/components/addOns/functional/ImageDescCarousel.jsx +0 -491
- package/dist/components/addOns/functional/NewUserAnalytics.jsx +0 -71
- package/dist/components/addOns/functional/ScheduleCarousel.jsx +0 -68
- package/dist/components/addOns/functional/aboutSections/AboutSection.jsx +0 -372
- package/dist/components/addOns/functional/aboutSections/constants/aboutSection.js +0 -65
- package/dist/components/addOns/functional/blogSections/BlogDashboard.jsx +0 -111
- package/dist/components/addOns/functional/blogSections/BlogFormPopUp.jsx +0 -465
- package/dist/components/addOns/functional/blogSections/BlogList.jsx +0 -170
- package/dist/components/addOns/functional/blogSections/BlogSidebar.jsx +0 -35
- package/dist/components/addOns/functional/blogSections/constants/blogDashboard.js +0 -28
- package/dist/components/addOns/functional/blogSections/constants/blogFormPopUp.js +0 -97
- package/dist/components/addOns/functional/blogSections/constants/blogList.js +0 -22
- package/dist/components/addOns/functional/blogSections/constants/blogSidebar.js +0 -15
- package/dist/components/addOns/functional/contactsDashboard/ContactsDashboard.jsx +0 -355
- package/dist/components/addOns/functional/contactsDashboard/constants/contactsDashboard.js +0 -70
- package/dist/components/addOns/functional/galleries/GalleryComplex.jsx +0 -605
- package/dist/components/addOns/functional/galleries/GallerySimple.jsx +0 -363
- package/dist/components/addOns/functional/galleries/constants/galleryComplex.js +0 -106
- package/dist/components/addOns/functional/galleries/constants/gallerySimple.js +0 -76
- package/dist/components/addOns/functional/schedules/ScheduleGridOne.jsx +0 -167
- package/dist/components/addOns/functional/schedules/ScheduleGridTwo.jsx +0 -100
- package/dist/components/addOns/functional/schedules/ScheduleGridTwoBasic.jsx +0 -97
- package/dist/components/addOns/functional/schedules/SchedulerForm.jsx +0 -188
- package/dist/components/addOns/functional/schedules/constants/ScheduleGridTwo.js +0 -40
- package/dist/components/addOns/functional/schedules/constants/ScheduleGridTwoBasic.js +0 -40
- package/dist/components/addOns/functional/schedules/constants/SchedulerForm.js +0 -65
- package/dist/components/addOns/functional/schedules/constants/scheduleGridOne.js +0 -54
- package/dist/components/addOns/non-functional/AnnouncementBanner.jsx +0 -24
- package/dist/components/addOns/non-functional/FeaturesSection.jsx +0 -38
- package/dist/components/addOns/non-functional/HeroSection.jsx +0 -71
- package/dist/components/addOns/non-functional/Heros/HeroSection.jsx +0 -71
- package/dist/components/addOns/non-functional/IconBubble.jsx +0 -36
- package/dist/components/addOns/non-functional/SampleCarousel.jsx +0 -114
- package/dist/components/addOns/non-functional/Testimonials.jsx +0 -177
- package/dist/components/addOns/non-functional/ThreeSetGallery.jsx +0 -40
- package/dist/components/addOns/non-functional/aboutSections/AboutSection.jsx +0 -35
- package/dist/components/addOns/non-functional/aboutSections/constants/aboutSection.js +0 -24
- package/dist/components/addOns/non-functional/imageCarousels/ProductSlider.jsx +0 -80
- package/dist/components/addOns/non-functional/imageCarousels/ProgramCarousel.jsx +0 -155
- package/dist/components/addOns/non-functional/imageCarousels/constants/programCarousel.js +0 -39
- package/dist/components/addOns/non-functional/imageCarousels/constants/programSlider.js +0 -36
- package/dist/components/addOns/non-functional/spinner.jsx +0 -13
- package/dist/components/footers/footer.jsx +0 -217
- package/dist/components/navBars/navbar.jsx +0 -159
- package/dist/components/other/accordion.jsx +0 -40
- package/dist/components/other/admin-menu.jsx +0 -34
- package/dist/components/other/alert-dialog.jsx +0 -64
- package/dist/components/other/alert.jsx +0 -41
- package/dist/components/other/aspect-ratio.jsx +0 -4
- package/dist/components/other/avatar.jsx +0 -31
- package/dist/components/other/badge.jsx +0 -32
- package/dist/components/other/breadcrumb.jsx +0 -57
- package/dist/components/other/button.jsx +0 -322
- package/dist/components/other/calendar.jsx +0 -43
- package/dist/components/other/card.jsx +0 -44
- package/dist/components/other/carousel.jsx +0 -140
- package/dist/components/other/chart.jsx +0 -182
- package/dist/components/other/checkbox.jsx +0 -26
- package/dist/components/other/collapsible.jsx +0 -6
- package/dist/components/other/command.jsx +0 -68
- package/dist/components/other/context-menu.jsx +0 -88
- package/dist/components/other/dialog.jsx +0 -60
- package/dist/components/other/drawer.jsx +0 -60
- package/dist/components/other/dropdown-menu.jsx +0 -90
- package/dist/components/other/form.jsx +0 -89
- package/dist/components/other/hover-card.jsx +0 -23
- package/dist/components/other/input-otp.jsx +0 -46
- package/dist/components/other/input.jsx +0 -19
- package/dist/components/other/label.jsx +0 -23
- package/dist/components/other/login-popup.jsx +0 -1
- package/dist/components/other/menubar.jsx +0 -96
- package/dist/components/other/mobile-icon.jsx +0 -11
- package/dist/components/other/navigation-menu.jsx +0 -62
- package/dist/components/other/pagination.jsx +0 -63
- package/dist/components/other/popover.jsx +0 -25
- package/dist/components/other/progress.jsx +0 -23
- package/dist/components/other/radio-group.jsx +0 -31
- package/dist/components/other/resizable.jsx +0 -29
- package/dist/components/other/scroll-area.jsx +0 -36
- package/dist/components/other/select.jsx +0 -83
- package/dist/components/other/separator.jsx +0 -21
- package/dist/components/other/sheet.jsx +0 -74
- package/dist/components/other/signup-popup.jsx +0 -1
- package/dist/components/other/skeleton.jsx +0 -17
- package/dist/components/other/slider.jsx +0 -26
- package/dist/components/other/social-icons.jsx +0 -15
- package/dist/components/other/sonner.jsx +0 -27
- package/dist/components/other/switch.jsx +0 -23
- package/dist/components/other/table.jsx +0 -56
- package/dist/components/other/tabs.jsx +0 -32
- package/dist/components/other/textarea.jsx +0 -19
- package/dist/components/other/toast.jsx +0 -58
- package/dist/components/other/toaster.jsx +0 -31
- package/dist/components/other/toggle-group.jsx +0 -41
- package/dist/components/other/toggle.jsx +0 -39
- package/dist/components/other/tooltip.jsx +0 -24
- package/dist/components/theme-provider.jsx +0 -18
- package/dist/components/types.js +0 -1
- package/dist/hooks/use-toast.js +0 -135
- package/dist/lib/auth-context.jsx +0 -144
- package/dist/lib/constants/about.js +0 -32
- package/dist/lib/constants/adRequest.js +0 -113
- package/dist/lib/constants/contact.js +0 -40
- package/dist/lib/constants/faq.js +0 -36
- package/dist/lib/constants/gallery.js +0 -42
- package/dist/lib/constants/page.js +0 -69
- package/dist/lib/constants/schedule.js +0 -71
- package/dist/lib/google-analytics.jsx +0 -148
- package/dist/lib/utils.js +0 -9
- package/dist/lib/verify-user.js +0 -142
- package/dist/middleware.js +0 -37
- package/dist/tailwind.config.js +0 -86
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/lib/auth-context.tsx +0 -131
- package/lib/verify-user.ts +0 -118
|
@@ -1,66 +1,71 @@
|
|
|
1
|
-
// components/addOns/functional/aboutSections/constants/aboutSection.ts
|
|
2
|
-
// Constants for hardcoded text in AboutSection.tsx, organized by purpose
|
|
3
|
-
|
|
4
|
-
export const ABOUT_SECTION = {
|
|
5
|
-
// UI Text for AboutSection
|
|
6
|
-
UI: {
|
|
7
|
-
// Blockquote text
|
|
8
|
-
BLOCKQUOTE_TEXT: "“
|
|
9
|
-
// Placeholder text when no image is available
|
|
10
|
-
NO_IMAGE_AVAILABLE: "No image available",
|
|
11
|
-
// Text when no description is available
|
|
12
|
-
NO_DESCRIPTION_AVAILABLE: "No about description available.",
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
// components/addOns/functional/aboutSections/constants/aboutSection.ts
|
|
2
|
+
// Constants for hardcoded text in AboutSection.tsx, organized by purpose
|
|
3
|
+
|
|
4
|
+
export const ABOUT_SECTION = {
|
|
5
|
+
// UI Text for AboutSection
|
|
6
|
+
UI: {
|
|
7
|
+
// Blockquote text
|
|
8
|
+
BLOCKQUOTE_TEXT: "“Family Owned & Operated Since 1954.”",
|
|
9
|
+
// Placeholder text when no image is available
|
|
10
|
+
NO_IMAGE_AVAILABLE: "No image available",
|
|
11
|
+
// Text when no description is available
|
|
12
|
+
NO_DESCRIPTION_AVAILABLE: "No about description available.",
|
|
13
|
+
// Fallback title when no data is available
|
|
14
|
+
FALLBACK_TITLE: "About Milton Supply Co",
|
|
15
|
+
// Fallback description when no data is available
|
|
16
|
+
FALLBACK_DESCRIPTION:
|
|
17
|
+
"Welcome to Milton Supply Co, your one-stop source for masonry supplies near Syracuse, NY.",
|
|
18
|
+
// Message when logged in as admin
|
|
19
|
+
ADMIN_LOGGED_IN_MESSAGE: "You are logged in as an admin.",
|
|
20
|
+
// Modal heading for edit form
|
|
21
|
+
MODAL_HEADING: "Edit About Section",
|
|
22
|
+
// Form label for title input
|
|
23
|
+
TITLE_LABEL: "About Title",
|
|
24
|
+
// Placeholder for title input
|
|
25
|
+
TITLE_PLACEHOLDER: "Enter the about title",
|
|
26
|
+
// Form label for image input
|
|
27
|
+
IMAGE_LABEL: "Update Image (optional)",
|
|
28
|
+
// Text showing selected image name
|
|
29
|
+
SELECTED_IMAGE_TEXT: "Selected: ${formImage.name}",
|
|
30
|
+
// Form label for description textarea
|
|
31
|
+
DESCRIPTION_LABEL: "About Description",
|
|
32
|
+
// Placeholder for description textarea
|
|
33
|
+
DESCRIPTION_PLACEHOLDER: "Enter the about description",
|
|
34
|
+
},
|
|
35
|
+
// Button Text for AboutSection
|
|
36
|
+
BUTTONS: {
|
|
37
|
+
// EditButton text
|
|
38
|
+
EDIT_BUTTON: "Edit",
|
|
39
|
+
// ReadMoreButton text when not expanded
|
|
40
|
+
READ_MORE_BUTTON: "Read More",
|
|
41
|
+
// ReadMoreButton text when expanded
|
|
42
|
+
READ_LESS_BUTTON: "Read Less",
|
|
43
|
+
// ActionButton text
|
|
44
|
+
GET_STARTED_BUTTON: "Get Started",
|
|
45
|
+
// UpdateButton text
|
|
46
|
+
UPDATE_BUTTON: "Update",
|
|
47
|
+
// UpdateButton text when submitting
|
|
48
|
+
SAVING_BUTTON: "Saving...",
|
|
49
|
+
// CancelButton text
|
|
50
|
+
CANCEL_BUTTON: "Cancel",
|
|
51
|
+
},
|
|
52
|
+
// Error Messages for AboutSection
|
|
53
|
+
ERRORS: {
|
|
54
|
+
// Error when no about data is returned
|
|
55
|
+
NO_DATA_FOUND: "About data not found",
|
|
56
|
+
// Error when fetch fails with status code
|
|
57
|
+
FETCH_FAILED: "Failed to fetch about data: ${response.status}",
|
|
58
|
+
// Generic error for fetch failure
|
|
59
|
+
FETCH_ERROR: "An error occurred while fetching about data",
|
|
60
|
+
// Error for non-admin update attempt
|
|
61
|
+
UNAUTHORIZED_UPDATE: "Unauthorized: Only admin can update about data",
|
|
62
|
+
// Error for invalid image type
|
|
63
|
+
INVALID_IMAGE_TYPE: "Only JPEG, PNG, or GIF images are allowed",
|
|
64
|
+
// Error when no authentication token is available
|
|
65
|
+
NO_AUTH_TOKEN: "No authentication token available",
|
|
66
|
+
// Error when update fails with status code
|
|
67
|
+
UPDATE_FAILED: "Failed to update about data: ${response.status}",
|
|
68
|
+
// Generic error for update failure
|
|
69
|
+
UPDATE_ERROR: "Failed to update about data",
|
|
70
|
+
},
|
|
66
71
|
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, useRef } from "react";
|
|
4
|
+
import { motion } from "framer-motion";
|
|
5
|
+
import { X } from "lucide-react";
|
|
6
|
+
import { UploadedImage } from "@/lib/types";
|
|
7
|
+
import Spinner from "@/components/addOns/non-functional/spinner";
|
|
8
|
+
|
|
9
|
+
export default function Banner() {
|
|
10
|
+
const [bannerData, setBannerData] = useState<UploadedImage | null>(null);
|
|
11
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
12
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
13
|
+
const bannerRef = useRef<HTMLDivElement>(null);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const fetchBanner = async () => {
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
console.log("Fetching banner from /api/gallery-data...");
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`/api/gallery-data?t=${Date.now()}`, {
|
|
21
|
+
headers: { "Content-Type": "application/json" },
|
|
22
|
+
cache: "no-store",
|
|
23
|
+
});
|
|
24
|
+
console.log("API Response Status:", response.status);
|
|
25
|
+
if (response.ok) {
|
|
26
|
+
const result = await response.json();
|
|
27
|
+
console.log("API Response Data:", result);
|
|
28
|
+
const images = Array.isArray(result.data)
|
|
29
|
+
? result.data.map((item: any) => ({
|
|
30
|
+
id: Number(item.id) || 0,
|
|
31
|
+
documentId: item.documentId || "",
|
|
32
|
+
title: item.title || "Untitled",
|
|
33
|
+
description: item.description || "",
|
|
34
|
+
url: item.image?.url
|
|
35
|
+
? item.image.url.startsWith("http")
|
|
36
|
+
? item.image.url
|
|
37
|
+
: `${process.env.STRAPI_API_URL}${item.image.url}`
|
|
38
|
+
: "",
|
|
39
|
+
createdAt: item.createdAt || new Date().toISOString(),
|
|
40
|
+
category: item.category || "none",
|
|
41
|
+
subCategory: item.subCategory || "",
|
|
42
|
+
favorite: item.favorite || false,
|
|
43
|
+
banner: item.banner || false,
|
|
44
|
+
startDate: item.startDate || undefined,
|
|
45
|
+
endDate: item.endDate || undefined,
|
|
46
|
+
}))
|
|
47
|
+
: [];
|
|
48
|
+
console.log("Mapped Images:", images);
|
|
49
|
+
|
|
50
|
+
const currentDate = new Date();
|
|
51
|
+
const banner = images.find((image: UploadedImage) => {
|
|
52
|
+
if (!image.banner) return false;
|
|
53
|
+
if (!image.startDate || !image.endDate) return false;
|
|
54
|
+
const start = new Date(image.startDate);
|
|
55
|
+
const end = new Date(image.endDate);
|
|
56
|
+
return start <= currentDate && currentDate <= end;
|
|
57
|
+
});
|
|
58
|
+
console.log("Selected Banner Data:", banner);
|
|
59
|
+
setBannerData(banner || null);
|
|
60
|
+
} else {
|
|
61
|
+
console.error("Banner: Gallery API Error", {
|
|
62
|
+
status: response.status,
|
|
63
|
+
statusText: response.statusText,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.error("Banner: Fetch Error", err);
|
|
68
|
+
} finally {
|
|
69
|
+
setIsLoading(false);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
fetchBanner();
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
// Handle click outside to close the banner
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
78
|
+
if (
|
|
79
|
+
bannerRef.current &&
|
|
80
|
+
!bannerRef.current.contains(event.target as Node) &&
|
|
81
|
+
isVisible
|
|
82
|
+
) {
|
|
83
|
+
setIsVisible(false);
|
|
84
|
+
console.log("Banner: Closed by clicking outside");
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
if (isVisible) {
|
|
89
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
90
|
+
} else {
|
|
91
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
96
|
+
};
|
|
97
|
+
}, [isVisible]);
|
|
98
|
+
|
|
99
|
+
if (isLoading) {
|
|
100
|
+
console.log("Banner: Showing Spinner");
|
|
101
|
+
return <Spinner />;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!isVisible || !bannerData) {
|
|
105
|
+
console.log("Banner: Not rendering", { isVisible, bannerData });
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log("Banner: Rendering with data", bannerData);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<motion.div
|
|
113
|
+
ref={bannerRef}
|
|
114
|
+
className="fixed top-0 left-0 right-0 bg-blue-500/80 backdrop-blur-sm text-white py-3 sm:py-6 z-[1200] shadow-md"
|
|
115
|
+
style={{
|
|
116
|
+
maskImage: "linear-gradient(to right, transparent 0%, black 20%, black 80%, transparent 100%)",
|
|
117
|
+
WebkitMaskImage: "linear-gradient(to right, transparent 0%, black 20%, black 80%, transparent 100%)",
|
|
118
|
+
}}
|
|
119
|
+
initial={{ y: -100, opacity: 0 }}
|
|
120
|
+
animate={{ y: 0, opacity: 1 }}
|
|
121
|
+
exit={{ y: -100, opacity: 0 }}
|
|
122
|
+
transition={{ duration: 0.5, ease: "easeOut" }}
|
|
123
|
+
>
|
|
124
|
+
<div className="max-w-7xl mx-auto flex items-center justify-between relative pr-10 sm:pr-14">
|
|
125
|
+
<div className="p-4 sm:p-6">
|
|
126
|
+
<h3 className="text-sm sm:text-base md:text-lg font-bold text-center">
|
|
127
|
+
{bannerData.title?.trim() &&
|
|
128
|
+
!bannerData.title.match(/Image \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z/)
|
|
129
|
+
? bannerData.title
|
|
130
|
+
: "Banner"}
|
|
131
|
+
</h3>
|
|
132
|
+
{bannerData.description && (
|
|
133
|
+
<p className="text-xs sm:text-sm text-center mt-2">
|
|
134
|
+
{bannerData.description.length > 100
|
|
135
|
+
? bannerData.description.slice(0, 100) + "..."
|
|
136
|
+
: bannerData.description}
|
|
137
|
+
</p>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
<button
|
|
141
|
+
onClick={() => setIsVisible(false)}
|
|
142
|
+
className="absolute right-2 sm:right-4 bg-blue-600/50 hover:bg-blue-700/70 text-white rounded-full p-1.5 sm:p-2 focus:outline-none focus:ring-2 focus:ring-blue-300 transition-colors"
|
|
143
|
+
aria-label="Close banner"
|
|
144
|
+
>
|
|
145
|
+
<X className="w-5 h-5 sm:w-8 sm:h-8" />
|
|
146
|
+
</button>
|
|
147
|
+
</div>
|
|
148
|
+
</motion.div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import { useAuth } from "@clerk/nextjs";
|
|
5
|
+
import { UploadedImage } from "@/lib/types";
|
|
6
|
+
import { GALLERY_COMPLEX } from "../galleries/constants/galleryComplex";
|
|
7
|
+
import Spinner from "@/components/addOns/non-functional/spinner";
|
|
8
|
+
import { SubmitButton } from "@/components/other/button";
|
|
9
|
+
|
|
10
|
+
interface BannerDashboardProps {
|
|
11
|
+
onUpdate?: (updatedImages: UploadedImage[]) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function BannerDashboard({ onUpdate }: BannerDashboardProps) {
|
|
15
|
+
const { getToken } = useAuth();
|
|
16
|
+
const [bannerData, setBannerData] = useState<UploadedImage | null>(null);
|
|
17
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
18
|
+
const [error, setError] = useState<string | null>(null);
|
|
19
|
+
const [form, setForm] = useState({
|
|
20
|
+
title: "",
|
|
21
|
+
description: "",
|
|
22
|
+
startDate: "",
|
|
23
|
+
endDate: "",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const fetchBanner = async () => {
|
|
28
|
+
setIsLoading(true);
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch(`/api/gallery-data?t=${Date.now()}`, {
|
|
31
|
+
headers: { "Content-Type": "application/json" },
|
|
32
|
+
cache: "no-store",
|
|
33
|
+
});
|
|
34
|
+
if (response.ok) {
|
|
35
|
+
const result = await response.json();
|
|
36
|
+
const images = Array.isArray(result.data)
|
|
37
|
+
? result.data.map((item: any) => ({
|
|
38
|
+
id: Number(item.id) || 0,
|
|
39
|
+
documentId: item.documentId || "",
|
|
40
|
+
title: item.title || "Untitled",
|
|
41
|
+
description: item.description || "",
|
|
42
|
+
url: item.image?.url
|
|
43
|
+
? item.image.url.startsWith("http")
|
|
44
|
+
? item.image.url
|
|
45
|
+
: `${process.env.STRAPI_API_URL}${item.image.url}`
|
|
46
|
+
: "",
|
|
47
|
+
createdAt: item.createdAt || new Date().toISOString(),
|
|
48
|
+
category: item.category || "none",
|
|
49
|
+
subCategory: item.subCategory || "",
|
|
50
|
+
favorite: item.favorite || false,
|
|
51
|
+
banner: item.banner || false,
|
|
52
|
+
startDate: item.startDate || undefined,
|
|
53
|
+
endDate: item.endDate || undefined,
|
|
54
|
+
}))
|
|
55
|
+
: [];
|
|
56
|
+
const banner = images.find((image: UploadedImage) => image.banner);
|
|
57
|
+
setBannerData((prev) =>
|
|
58
|
+
JSON.stringify(prev) !== JSON.stringify(banner) ? banner : prev
|
|
59
|
+
);
|
|
60
|
+
if (banner) {
|
|
61
|
+
setForm({
|
|
62
|
+
title: banner.title || "",
|
|
63
|
+
description: banner.description || "",
|
|
64
|
+
startDate: banner.startDate
|
|
65
|
+
? new Date(banner.startDate).toISOString().slice(0, 10)
|
|
66
|
+
: "",
|
|
67
|
+
endDate: banner.endDate
|
|
68
|
+
? new Date(banner.endDate).toISOString().slice(0, 10)
|
|
69
|
+
: "",
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
setError("Failed to fetch banner data");
|
|
74
|
+
}
|
|
75
|
+
} catch (err) {
|
|
76
|
+
setError("Error fetching banner data");
|
|
77
|
+
console.error("BannerDashboard: Fetch Error", err);
|
|
78
|
+
} finally {
|
|
79
|
+
setIsLoading(false);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
fetchBanner();
|
|
83
|
+
}, []);
|
|
84
|
+
|
|
85
|
+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
if (!bannerData) {
|
|
88
|
+
setError("No banner image selected");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!form.startDate || !form.endDate) {
|
|
92
|
+
setError("Both start date and end date are required");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (new Date(form.startDate) > new Date(form.endDate)) {
|
|
96
|
+
setError("End date must be after start date");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
setIsLoading(true);
|
|
100
|
+
try {
|
|
101
|
+
const token = await getToken();
|
|
102
|
+
if (!token) {
|
|
103
|
+
setError(GALLERY_COMPLEX.ERRORS.AUTHENTICATION_ERROR);
|
|
104
|
+
console.error("BannerDashboard: No authentication token available", {
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const formData = new FormData();
|
|
111
|
+
formData.append("documentId", bannerData.documentId);
|
|
112
|
+
formData.append("title", form.title);
|
|
113
|
+
formData.append("description", form.description);
|
|
114
|
+
formData.append("banner", String(bannerData.banner));
|
|
115
|
+
formData.append("startDate", new Date(form.startDate).toISOString());
|
|
116
|
+
formData.append("endDate", new Date(form.endDate).toISOString());
|
|
117
|
+
|
|
118
|
+
console.log("Submitting FormData:", Object.fromEntries(formData));
|
|
119
|
+
|
|
120
|
+
const response = await fetch("/api/gallery-data", {
|
|
121
|
+
method: "PUT",
|
|
122
|
+
headers: {
|
|
123
|
+
Authorization: `Bearer ${token}`,
|
|
124
|
+
},
|
|
125
|
+
body: formData,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
const errorData = await response.json();
|
|
130
|
+
console.error("BannerDashboard: Update failed", {
|
|
131
|
+
status: response.status,
|
|
132
|
+
errorData,
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
});
|
|
135
|
+
if (response.status === 401) {
|
|
136
|
+
setError(GALLERY_COMPLEX.ERRORS.AUTHENTICATION_ERROR);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(
|
|
140
|
+
errorData.error ||
|
|
141
|
+
GALLERY_COMPLEX.ERRORS.EDIT_FAILED_STATUS.replace(
|
|
142
|
+
"${response.status}",
|
|
143
|
+
response.status.toString()
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const { data } = await response.json();
|
|
149
|
+
if (onUpdate) {
|
|
150
|
+
onUpdate(data || []);
|
|
151
|
+
}
|
|
152
|
+
setBannerData((prev) =>
|
|
153
|
+
prev
|
|
154
|
+
? {
|
|
155
|
+
...prev,
|
|
156
|
+
title: form.title,
|
|
157
|
+
description: form.description,
|
|
158
|
+
startDate: form.startDate
|
|
159
|
+
? new Date(form.startDate).toISOString()
|
|
160
|
+
: undefined,
|
|
161
|
+
endDate: form.endDate
|
|
162
|
+
? new Date(form.endDate).toISOString()
|
|
163
|
+
: undefined,
|
|
164
|
+
banner: prev.banner,
|
|
165
|
+
}
|
|
166
|
+
: prev
|
|
167
|
+
);
|
|
168
|
+
setError(null);
|
|
169
|
+
} catch (err) {
|
|
170
|
+
console.error("BannerDashboard: Update Error", {
|
|
171
|
+
error: err instanceof Error ? err.message : "Unknown error",
|
|
172
|
+
timestamp: new Date().toISOString(),
|
|
173
|
+
});
|
|
174
|
+
setError(
|
|
175
|
+
err instanceof Error ? err.message : GALLERY_COMPLEX.ERRORS.EDIT_FAILED
|
|
176
|
+
);
|
|
177
|
+
} finally {
|
|
178
|
+
setIsLoading(false);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
if (isLoading) {
|
|
183
|
+
return (
|
|
184
|
+
<div className="p-4 sm:p-6 bg-gray-800 rounded-lg min-h-[200px] flex items-center justify-center">
|
|
185
|
+
<Spinner />
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<div className="p-4 sm:p-6 bg-gray-800 rounded-lg shadow-lg max-w-2xl mx-auto">
|
|
192
|
+
<h3 className="text-lg sm:text-xl font-bold text-white mb-4">Manage Banner</h3>
|
|
193
|
+
{error && <p className="text-red-500 text-sm mb-4">{error}</p>}
|
|
194
|
+
{bannerData ? (
|
|
195
|
+
<form onSubmit={handleSubmit} className="flex flex-col space-y-4">
|
|
196
|
+
<div>
|
|
197
|
+
<label
|
|
198
|
+
htmlFor="title"
|
|
199
|
+
className="block text-sm font-medium text-gray-300 mb-1"
|
|
200
|
+
>
|
|
201
|
+
Banner Title
|
|
202
|
+
</label>
|
|
203
|
+
<input
|
|
204
|
+
id="title"
|
|
205
|
+
type="text"
|
|
206
|
+
value={form.title}
|
|
207
|
+
onChange={(e) => setForm({ ...form, title: e.target.value })}
|
|
208
|
+
className="p-2 bg-gray-700 text-white rounded-lg w-full focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm sm:text-base"
|
|
209
|
+
disabled={isLoading}
|
|
210
|
+
placeholder="Enter banner title"
|
|
211
|
+
/>
|
|
212
|
+
</div>
|
|
213
|
+
<div>
|
|
214
|
+
<label
|
|
215
|
+
htmlFor="description"
|
|
216
|
+
className="block text-sm font-medium text-gray-300 mb-1"
|
|
217
|
+
>
|
|
218
|
+
Banner Description
|
|
219
|
+
</label>
|
|
220
|
+
<textarea
|
|
221
|
+
id="description"
|
|
222
|
+
value={form.description}
|
|
223
|
+
onChange={(e) => setForm({ ...form, description: e.target.value })}
|
|
224
|
+
className="p-2 bg-gray-700 text-white rounded-lg w-full focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm sm:text-base"
|
|
225
|
+
disabled={isLoading}
|
|
226
|
+
placeholder="Enter banner description"
|
|
227
|
+
rows={4}
|
|
228
|
+
/>
|
|
229
|
+
</div>
|
|
230
|
+
<div>
|
|
231
|
+
<label
|
|
232
|
+
htmlFor="start-date"
|
|
233
|
+
className="block text-sm font-medium text-gray-300 mb-1"
|
|
234
|
+
>
|
|
235
|
+
Start Date
|
|
236
|
+
</label>
|
|
237
|
+
<input
|
|
238
|
+
id="start-date"
|
|
239
|
+
type="date"
|
|
240
|
+
value={form.startDate}
|
|
241
|
+
onChange={(e) => setForm({ ...form, startDate: e.target.value })}
|
|
242
|
+
className="p-2 bg-gray-700 text-white rounded-lg w-full focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm sm:text-base"
|
|
243
|
+
disabled={isLoading}
|
|
244
|
+
required
|
|
245
|
+
/>
|
|
246
|
+
</div>
|
|
247
|
+
<div>
|
|
248
|
+
<label
|
|
249
|
+
htmlFor="end-date"
|
|
250
|
+
className="block text-sm font-medium text-gray-300 mb-1"
|
|
251
|
+
>
|
|
252
|
+
End Date
|
|
253
|
+
</label>
|
|
254
|
+
<input
|
|
255
|
+
id="end-date"
|
|
256
|
+
type="date"
|
|
257
|
+
value={form.endDate}
|
|
258
|
+
onChange={(e) => setForm({ ...form, endDate: e.target.value })}
|
|
259
|
+
className="p-2 bg-gray-700 text-white rounded-lg w-full focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm sm:text-base"
|
|
260
|
+
disabled={isLoading}
|
|
261
|
+
required
|
|
262
|
+
/>
|
|
263
|
+
</div>
|
|
264
|
+
<div className="flex justify-end">
|
|
265
|
+
<SubmitButton
|
|
266
|
+
type="submit"
|
|
267
|
+
disabled={isLoading}
|
|
268
|
+
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:outline-none disabled:bg-blue-400 text-sm sm:text-base"
|
|
269
|
+
>
|
|
270
|
+
{isLoading
|
|
271
|
+
? GALLERY_COMPLEX.BUTTONS.SAVING_BUTTON
|
|
272
|
+
: GALLERY_COMPLEX.BUTTONS.SAVE_BUTTON}
|
|
273
|
+
</SubmitButton>
|
|
274
|
+
</div>
|
|
275
|
+
</form>
|
|
276
|
+
) : (
|
|
277
|
+
<p className="text-gray-400 text-sm sm:text-base">
|
|
278
|
+
No banner image found. Please upload an image with banner: true in the gallery.
|
|
279
|
+
</p>
|
|
280
|
+
)}
|
|
281
|
+
</div>
|
|
282
|
+
);
|
|
283
|
+
}
|