@devvistatech/devvista-kit 0.0.12 → 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/README.md +40 -0
- package/app/ClientLayout.tsx +66 -0
- package/app/about/page.tsx +11 -248
- package/app/adRequest/page.tsx +101 -25
- package/app/admin-profile/page.tsx +123 -0
- package/app/analytics/page.tsx +41 -5
- package/app/api/about/route.ts +2 -18
- package/app/api/adRequest/route.ts +7 -27
- package/app/api/analytics/[reportType]/route.ts +1 -64
- package/app/api/bio/route.ts +1 -17
- package/app/api/blog/route.ts +1 -19
- package/app/api/contacts/route.ts +1 -46
- package/app/api/files/route.ts +1 -15
- package/app/api/gallery-data/route.ts +53 -61
- package/app/api/schedule/route.ts +5 -21
- package/app/api/signup/route.ts +129 -0
- package/app/api/sync-user/route.ts +268 -94
- package/app/api/verify-admin/route.ts +46 -0
- package/app/blog/[id]/page.tsx +71 -52
- package/app/blog/page.tsx +43 -10
- package/app/favicon.ico +0 -0
- package/app/gallery/page.tsx +27 -6
- package/app/layout.tsx +31 -82
- package/app/page.tsx +20 -311
- 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 +78 -40
- package/bin/init.js +0 -12
- package/components/addOns/functional/ClassList.tsx +21 -17
- package/components/addOns/functional/ProductList.tsx +1027 -0
- package/components/addOns/functional/aboutSections/AboutSection.tsx +107 -70
- package/components/addOns/functional/aboutSections/constants/aboutSection.ts +9 -4
- 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 +1 -1
- package/components/addOns/functional/blogSections/BlogFormPopUp.tsx +2 -1
- package/components/addOns/functional/{ImageDescCarousel.tsx → carousels/ImageDescCarousel.tsx} +166 -57
- package/components/addOns/functional/carousels/ProductDescCarousel.tsx +1129 -0
- package/components/addOns/functional/{ScheduleCarousel.tsx → carousels/ScheduleCarousel.tsx} +110 -50
- 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 +1 -1
- 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 +468 -267
- package/components/addOns/functional/galleries/GallerySimple.tsx +78 -50
- package/components/addOns/functional/galleries/ThreeSetGallery.tsx +260 -0
- package/components/addOns/functional/schedules/ScheduleGridOne.tsx +22 -8
- package/components/addOns/functional/schedules/ScheduleGridTwo.tsx +12 -7
- package/components/addOns/functional/schedules/ScheduleGridTwoBasic.tsx +12 -7
- package/components/addOns/non-functional/SampleCarousel.tsx +3 -3
- package/components/addOns/non-functional/ThreeSetGallery.tsx +3 -3
- 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} +17 -15
- 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 +6 -6
- package/components/addOns/non-functional/imageCarousels/ProgramCarousel.tsx +10 -10
- package/components/footers/footer.tsx +161 -198
- package/components/other/admin-menu.tsx +1 -1
- package/lib/auth/auth-context.tsx +225 -0
- package/lib/auth/auth-utils.tsx +30 -0
- package/lib/constants/adRequest.ts +199 -56
- package/lib/constants/admin-profile.ts +12 -0
- package/lib/constants/page.ts +15 -15
- package/lib/google/google-analytics-tracking.tsx +44 -0
- package/lib/types.ts +235 -0
- package/lib/utils/compressImage.tsx +32 -0
- package/middleware.ts +9 -5
- package/next.config.js +1 -1
- package/package.json +3 -2
- package/public/images/test.png +0 -0
- 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/lib/auth-context.tsx +0 -131
- package/lib/verify-user.ts +0 -118
- /package/lib/{google-analytics.tsx → google/google-analytics.tsx} +0 -0
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { motion } from "framer-motion";
|
|
4
|
-
import Image from "next/image";
|
|
5
|
-
import { useState, useEffect } from "react";
|
|
6
|
-
import { EditIconButton, ToggleButton, UpdateButton, CancelButton, CloseButton } from "@/components/other/button";
|
|
7
|
-
import Spinner from "@/components/addOns/non-functional/spinner";
|
|
8
|
-
import { X } from "lucide-react";
|
|
9
|
-
|
|
10
|
-
interface BioContent {
|
|
11
|
-
id: number;
|
|
12
|
-
documentId: string;
|
|
13
|
-
title: string;
|
|
14
|
-
description: string;
|
|
15
|
-
bio: boolean;
|
|
16
|
-
image?: { url: string; id: number };
|
|
17
|
-
createdAt: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface StrapiUser {
|
|
21
|
-
id: number;
|
|
22
|
-
username: string;
|
|
23
|
-
email: string;
|
|
24
|
-
businessAdminId?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface BioSectionProps {
|
|
28
|
-
user: StrapiUser | null;
|
|
29
|
-
authLoading: boolean;
|
|
30
|
-
bioImageUrl: string | null;
|
|
31
|
-
bioText: string | null;
|
|
32
|
-
bioTitle: string | null;
|
|
33
|
-
error: string | null;
|
|
34
|
-
isLoading: boolean;
|
|
35
|
-
setBioImageUrl: (url: string | null) => void;
|
|
36
|
-
setBioText: (text: string | null) => void;
|
|
37
|
-
setBioTitle: (title: string | null) => void;
|
|
38
|
-
setError: (error: string | null) => void;
|
|
39
|
-
handlePatchSubmit: (
|
|
40
|
-
e: React.FormEvent,
|
|
41
|
-
formTitle: string,
|
|
42
|
-
formDescription: string,
|
|
43
|
-
formImage: File | null,
|
|
44
|
-
onSuccess: () => void
|
|
45
|
-
) => Promise<void>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function BioSection({
|
|
49
|
-
user,
|
|
50
|
-
authLoading,
|
|
51
|
-
bioImageUrl,
|
|
52
|
-
bioText,
|
|
53
|
-
bioTitle,
|
|
54
|
-
error,
|
|
55
|
-
isLoading,
|
|
56
|
-
setBioImageUrl,
|
|
57
|
-
setBioText,
|
|
58
|
-
setBioTitle,
|
|
59
|
-
setError,
|
|
60
|
-
handlePatchSubmit,
|
|
61
|
-
}: BioSectionProps) {
|
|
62
|
-
const [isMobile, setIsMobile] = useState(false);
|
|
63
|
-
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
|
64
|
-
const [formTitle, setFormTitle] = useState<string>(bioTitle || "");
|
|
65
|
-
const [formDescription, setFormDescription] = useState<string>(bioText || "");
|
|
66
|
-
const [formImage, setFormImage] = useState<File | null>(null);
|
|
67
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
68
|
-
const [isExpanded, setIsExpanded] = useState(false);
|
|
69
|
-
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
const debounce = (fn: () => void, delay: number) => {
|
|
72
|
-
let timeout: NodeJS.Timeout;
|
|
73
|
-
return () => {
|
|
74
|
-
clearTimeout(timeout);
|
|
75
|
-
timeout = setTimeout(fn, delay);
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const checkMobile = debounce(() => {
|
|
80
|
-
setIsMobile(window.innerWidth < 768);
|
|
81
|
-
}, 100);
|
|
82
|
-
|
|
83
|
-
checkMobile();
|
|
84
|
-
window.addEventListener("resize", checkMobile);
|
|
85
|
-
return () => window.removeEventListener("resize", checkMobile);
|
|
86
|
-
}, []);
|
|
87
|
-
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
const event = new CustomEvent("modalStateChange", {
|
|
90
|
-
detail: { isOpen: isEditModalOpen },
|
|
91
|
-
});
|
|
92
|
-
window.dispatchEvent(event);
|
|
93
|
-
}, [isEditModalOpen]);
|
|
94
|
-
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
if (isEditModalOpen) {
|
|
97
|
-
// Store current scroll position
|
|
98
|
-
const scrollY = window.scrollY;
|
|
99
|
-
// Prevent background scrolling
|
|
100
|
-
document.body.style.position = "fixed";
|
|
101
|
-
document.body.style.top = `-${scrollY}px`;
|
|
102
|
-
document.body.style.width = "100%";
|
|
103
|
-
document.body.classList.add("overflow-hidden");
|
|
104
|
-
|
|
105
|
-
return () => {
|
|
106
|
-
// Restore scroll position and remove styles
|
|
107
|
-
const scrollYRestored = parseInt(document.body.style.top || "0", 10) * -1;
|
|
108
|
-
document.body.style.position = "";
|
|
109
|
-
document.body.style.top = "";
|
|
110
|
-
document.body.style.width = "";
|
|
111
|
-
document.body.classList.remove("overflow-hidden");
|
|
112
|
-
window.scrollTo(0, scrollYRestored);
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}, [isEditModalOpen]);
|
|
116
|
-
|
|
117
|
-
const openEditModal = () => {
|
|
118
|
-
setFormTitle(bioTitle || "");
|
|
119
|
-
setFormDescription(bioText || "");
|
|
120
|
-
setFormImage(null);
|
|
121
|
-
setIsEditModalOpen(true);
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const handleCancelEdit = () => {
|
|
125
|
-
setIsEditModalOpen(false);
|
|
126
|
-
setFormTitle(bioTitle || "");
|
|
127
|
-
setFormDescription(bioText || "");
|
|
128
|
-
setFormImage(null);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
useEffect(() => {
|
|
132
|
-
const handleEsc = (e: KeyboardEvent) => {
|
|
133
|
-
if (e.key === "Escape" && isEditModalOpen) {
|
|
134
|
-
handleCancelEdit();
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
window.addEventListener("keydown", handleEsc);
|
|
138
|
-
return () => window.removeEventListener("keydown", handleEsc);
|
|
139
|
-
}, [isEditModalOpen]);
|
|
140
|
-
|
|
141
|
-
const isAdmin = !!user?.businessAdminId;
|
|
142
|
-
|
|
143
|
-
const sectionVariants = {
|
|
144
|
-
hidden: { opacity: 0, y: 20 },
|
|
145
|
-
visible: {
|
|
146
|
-
opacity: 1,
|
|
147
|
-
y: 0,
|
|
148
|
-
transition: { duration: isMobile ? 0.3 : 0.5, ease: "easeOut" },
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const itemVariants = {
|
|
153
|
-
hidden: { opacity: 0, y: 10 },
|
|
154
|
-
visible: {
|
|
155
|
-
opacity: 1,
|
|
156
|
-
y: 0,
|
|
157
|
-
transition: { duration: isMobile ? 0.3 : 0.5, ease: "easeOut" },
|
|
158
|
-
},
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const modalVariants = {
|
|
162
|
-
hidden: { opacity: 0, y: "100vh" },
|
|
163
|
-
visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: [0.16, 1, 0.3, 1] } },
|
|
164
|
-
exit: { opacity: 0, y: "100vh", transition: { duration: 0.3, ease: "easeIn" } },
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const paragraphs = bioText
|
|
168
|
-
? bioText.split("\n").filter((paragraph) => paragraph.trim() !== "")
|
|
169
|
-
: [];
|
|
170
|
-
|
|
171
|
-
return (
|
|
172
|
-
<div className="w-full">
|
|
173
|
-
<style jsx>{`
|
|
174
|
-
:root {
|
|
175
|
-
--jubilee: #F47C7C;
|
|
176
|
-
--exuberant-blue: #FF69B4;
|
|
177
|
-
--modern-purple: #D946EF;
|
|
178
|
-
--green-primary: #1a3c34;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.glassmorphism {
|
|
182
|
-
background: rgba(255, 255, 255, 0.08);
|
|
183
|
-
backdrop-filter: blur(10px);
|
|
184
|
-
border: 2px solid transparent;
|
|
185
|
-
border-image: linear-gradient(45deg, var(--exuberant-blue), var(--jubilee), var(--modern-purple)) 1;
|
|
186
|
-
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.1);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
.modal-form {
|
|
190
|
-
max-height: 90vh;
|
|
191
|
-
overflow-y: auto;
|
|
192
|
-
-webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.modal-form input,
|
|
196
|
-
.modal-form textarea {
|
|
197
|
-
font-size: 0.875rem;
|
|
198
|
-
padding: 0.5rem;
|
|
199
|
-
border-radius: 0.375rem;
|
|
200
|
-
background: #374151;
|
|
201
|
-
color: #f3f4f6;
|
|
202
|
-
border: 1px solid #4b5563;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.modal-form input:focus,
|
|
206
|
-
.modal-form textarea:focus {
|
|
207
|
-
outline: none;
|
|
208
|
-
ring: 2px solid #3b82f6;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.modal-form label {
|
|
212
|
-
font-size: 0.875rem;
|
|
213
|
-
color: #d1d5db;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
body.overflow-hidden {
|
|
217
|
-
overflow: hidden;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
@supports not (backdrop-filter: blur(10px)) {
|
|
221
|
-
.glassmorphism {
|
|
222
|
-
background: rgba(255, 255, 255, 0.2);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
@media (max-width: 768px) {
|
|
227
|
-
.glassmorphism {
|
|
228
|
-
backdrop-filter: none;
|
|
229
|
-
background: rgba(255, 255, 255, 0.2);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.modal-form input,
|
|
233
|
-
.modal-form textarea {
|
|
234
|
-
font-size: 0.875rem;
|
|
235
|
-
padding: 0.5rem;
|
|
236
|
-
border-radius: 0.375rem;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.modal-form label {
|
|
240
|
-
font-size: 0.875rem;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.modal-form .flex {
|
|
244
|
-
flex-direction: column;
|
|
245
|
-
gap: 0.5rem;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.modal-form textarea {
|
|
249
|
-
min-height: 80px;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
@media (max-width: 320px) {
|
|
254
|
-
.modal-form input,
|
|
255
|
-
.modal-form textarea {
|
|
256
|
-
font-size: 0.75rem;
|
|
257
|
-
padding: 0.5rem;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
.modal-form label {
|
|
261
|
-
font-size: 0.75rem;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
`}</style>
|
|
265
|
-
<motion.div
|
|
266
|
-
variants={sectionVariants}
|
|
267
|
-
initial="hidden"
|
|
268
|
-
animate="visible"
|
|
269
|
-
className="mb-24 max-w-[200rem] mx-auto px-8 sm:px-10"
|
|
270
|
-
>
|
|
271
|
-
<div className="flex flex-col md:flex-row gap-10 items-start min-h-[fit-content]">
|
|
272
|
-
<motion.div
|
|
273
|
-
variants={itemVariants}
|
|
274
|
-
className="relative h-[40vh] min-h-[400px] sm:h-[50vh] lg:h-[600px] rounded-[1.5rem] overflow-hidden glassmorphism w-full mx-auto max-w-3xl md:max-w-none md:mx-0"
|
|
275
|
-
>
|
|
276
|
-
{bioImageUrl ? (
|
|
277
|
-
<div className="relative w-full h-full">
|
|
278
|
-
<Image
|
|
279
|
-
src={bioImageUrl}
|
|
280
|
-
alt="Portrait of Kathy Caiello"
|
|
281
|
-
fill
|
|
282
|
-
className="object-cover rounded-[1rem] transition-transform duration-700 hover:scale-110"
|
|
283
|
-
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
|
284
|
-
loading="lazy"
|
|
285
|
-
quality={85}
|
|
286
|
-
/>
|
|
287
|
-
<div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-500"></div>
|
|
288
|
-
{isAdmin && (
|
|
289
|
-
<div className="absolute top-2 right-0 flex">
|
|
290
|
-
<EditIconButton
|
|
291
|
-
onClick={(e) => {
|
|
292
|
-
e.stopPropagation();
|
|
293
|
-
openEditModal();
|
|
294
|
-
}}
|
|
295
|
-
/>
|
|
296
|
-
</div>
|
|
297
|
-
)}
|
|
298
|
-
</div>
|
|
299
|
-
) : (
|
|
300
|
-
<div className="w-full h-full flex items-center justify-center">
|
|
301
|
-
<p className="text-gray-600 text-lg">No image available</p>
|
|
302
|
-
</div>
|
|
303
|
-
)}
|
|
304
|
-
</motion.div>
|
|
305
|
-
<motion.div
|
|
306
|
-
variants={itemVariants}
|
|
307
|
-
className="space-y-6 min-h-[fit-content] h-auto w-full relative"
|
|
308
|
-
>
|
|
309
|
-
{bioTitle && (
|
|
310
|
-
<motion.h2
|
|
311
|
-
variants={itemVariants}
|
|
312
|
-
className="text-2xl sm:text-3xl font-bold text-gray-800"
|
|
313
|
-
>
|
|
314
|
-
{bioTitle}
|
|
315
|
-
</motion.h2>
|
|
316
|
-
)}
|
|
317
|
-
{paragraphs.length > 0 ? (
|
|
318
|
-
<>
|
|
319
|
-
{paragraphs
|
|
320
|
-
.slice(0, isExpanded ? paragraphs.length : 3)
|
|
321
|
-
.map((paragraph, index) => (
|
|
322
|
-
<motion.p
|
|
323
|
-
key={index}
|
|
324
|
-
variants={itemVariants}
|
|
325
|
-
className="text-gray-800 text-base sm:text-lg md:text-xl leading-relaxed font-medium"
|
|
326
|
-
>
|
|
327
|
-
{paragraph}
|
|
328
|
-
</motion.p>
|
|
329
|
-
))}
|
|
330
|
-
{paragraphs.length > 3 && (
|
|
331
|
-
<motion.div variants={itemVariants} className="mt-4">
|
|
332
|
-
<ToggleButton
|
|
333
|
-
variant="toggle-bio"
|
|
334
|
-
onClick={() => setIsExpanded(!isExpanded)}
|
|
335
|
-
>
|
|
336
|
-
{isExpanded ? "Read Less" : "Read More"}
|
|
337
|
-
</ToggleButton>
|
|
338
|
-
</motion.div>
|
|
339
|
-
)}
|
|
340
|
-
</>
|
|
341
|
-
) : (
|
|
342
|
-
<motion.p
|
|
343
|
-
variants={itemVariants}
|
|
344
|
-
className="text-gray-600 text-base sm:text-lg md:text-xl leading-relaxed font-medium"
|
|
345
|
-
>
|
|
346
|
-
No bio description available.
|
|
347
|
-
</motion.p>
|
|
348
|
-
)}
|
|
349
|
-
</motion.div>
|
|
350
|
-
</div>
|
|
351
|
-
{error && (
|
|
352
|
-
<p className="text-red-400 text-base sm:text-lg md:text-xl text-center mt-4">{error}</p>
|
|
353
|
-
)}
|
|
354
|
-
</motion.div>
|
|
355
|
-
{isEditModalOpen && (
|
|
356
|
-
<motion.div
|
|
357
|
-
variants={modalVariants}
|
|
358
|
-
initial="hidden"
|
|
359
|
-
animate="visible"
|
|
360
|
-
exit="exit"
|
|
361
|
-
className="fixed inset-0 bg-black/90 flex items-center justify-center z-[10000] p-4 isolate"
|
|
362
|
-
onClick={handleCancelEdit}
|
|
363
|
-
aria-modal="true"
|
|
364
|
-
role="dialog"
|
|
365
|
-
>
|
|
366
|
-
<div
|
|
367
|
-
className="relative max-w-5xl w-full mx-4 p-6 bg-gray-800/50 border border-gray-700/50 rounded-lg shadow-lg max-h-[90vh] overflow-y-auto modal-form"
|
|
368
|
-
onClick={(e) => e.stopPropagation()}
|
|
369
|
-
>
|
|
370
|
-
<CloseButton onClick={handleCancelEdit}>
|
|
371
|
-
<X className="h-6 w-6 sm:h-8 sm:w-8" />
|
|
372
|
-
</CloseButton>
|
|
373
|
-
<h3 className="text-xl font-bold text-white mb-4">Edit Bio</h3>
|
|
374
|
-
<form
|
|
375
|
-
onSubmit={(e) => {
|
|
376
|
-
setIsSubmitting(true);
|
|
377
|
-
handlePatchSubmit(e, formTitle, formDescription, formImage, () => {
|
|
378
|
-
setIsEditModalOpen(false);
|
|
379
|
-
}).finally(() => setIsSubmitting(false));
|
|
380
|
-
}}
|
|
381
|
-
className="space-y-4 modal-form"
|
|
382
|
-
>
|
|
383
|
-
<div>
|
|
384
|
-
<label
|
|
385
|
-
htmlFor="bioTitle"
|
|
386
|
-
className="block text-sm font-medium text-gray-300 mb-1"
|
|
387
|
-
>
|
|
388
|
-
Bio Title
|
|
389
|
-
</label>
|
|
390
|
-
<input
|
|
391
|
-
id="bioTitle"
|
|
392
|
-
type="text"
|
|
393
|
-
value={formTitle}
|
|
394
|
-
onChange={(e) => setFormTitle(e.target.value)}
|
|
395
|
-
className="w-full p-2 rounded bg-gray-700 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
|
|
396
|
-
placeholder="Enter the bio title"
|
|
397
|
-
/>
|
|
398
|
-
</div>
|
|
399
|
-
<div>
|
|
400
|
-
<label
|
|
401
|
-
htmlFor="bioImage"
|
|
402
|
-
className="block text-sm font-medium text-gray-300 mb-1"
|
|
403
|
-
>
|
|
404
|
-
Update Image (optional)
|
|
405
|
-
</label>
|
|
406
|
-
<input
|
|
407
|
-
id="bioImage"
|
|
408
|
-
type="file"
|
|
409
|
-
accept="image/jpeg,image/png,image/gif"
|
|
410
|
-
onChange={(e) => setFormImage(e.target.files?.[0] || null)}
|
|
411
|
-
className="w-full p-2 rounded bg-gray-700 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
|
|
412
|
-
/>
|
|
413
|
-
{formImage && (
|
|
414
|
-
<p className="mt-2 text-gray-300 text-sm">Selected: {formImage.name}</p>
|
|
415
|
-
)}
|
|
416
|
-
</div>
|
|
417
|
-
<div>
|
|
418
|
-
<label
|
|
419
|
-
htmlFor="bioDescription"
|
|
420
|
-
className="block text-sm font-medium text-gray-300 mb-1"
|
|
421
|
-
>
|
|
422
|
-
Update Description
|
|
423
|
-
</label>
|
|
424
|
-
<textarea
|
|
425
|
-
id="bioDescription"
|
|
426
|
-
value={formDescription}
|
|
427
|
-
onChange={(e) => setFormDescription(e.target.value)}
|
|
428
|
-
className="w-full p-2 rounded bg-gray-700 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm min-h-[80px]"
|
|
429
|
-
placeholder="Enter the bio description"
|
|
430
|
-
/>
|
|
431
|
-
</div>
|
|
432
|
-
<div className="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-3">
|
|
433
|
-
<UpdateButton type="submit" disabled={isSubmitting}>
|
|
434
|
-
{isSubmitting ? "Saving..." : "Update"}
|
|
435
|
-
</UpdateButton>
|
|
436
|
-
<CancelButton type="button" onClick={handleCancelEdit}>
|
|
437
|
-
Cancel
|
|
438
|
-
</CancelButton>
|
|
439
|
-
</div>
|
|
440
|
-
{error && <p className="text-red-400 text-sm font-medium">{error}</p>}
|
|
441
|
-
</form>
|
|
442
|
-
</div>
|
|
443
|
-
</motion.div>
|
|
444
|
-
)}
|
|
445
|
-
</div>
|
|
446
|
-
);
|
|
447
|
-
}
|