@titas_mallick/wedding-site-gen 1.1.0 → 2.0.0
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 +70 -184
- package/app/api/email-reminders/route.ts +240 -0
- package/app/couple/page.tsx +4 -4
- package/app/game/page.tsx +298 -0
- package/app/guestbook/page.tsx +270 -152
- package/app/invitation/[slug]/layout.tsx +4 -2
- package/app/invitation/[slug]/page.tsx +303 -84
- package/app/invitation/actions.ts +49 -0
- package/app/invitation/maker/auth.js +1 -1
- package/app/invitation/maker/guestAdder.js +4 -0
- package/app/invitation/maker/guestShower.js +39 -8
- package/app/invitation/maker/layout.tsx +1 -1
- package/app/invitation/maker/page.js +9 -7
- package/app/invitation/maker/rsvpViewer.js +90 -8
- package/app/layout.tsx +40 -14
- package/app/mark-the-dates/page.tsx +8 -2
- package/app/page.tsx +7 -1
- package/app/providers.tsx +1 -1
- package/app/sagun/page.tsx +224 -76
- package/app/song-requests/page.tsx +242 -105
- package/app/sukanya/page.tsx +9 -13
- package/app/titas/page.tsx +8 -24
- package/app/travel-guide/page.tsx +361 -120
- package/app/updates/maker/page.js +2 -2
- package/app/updates/overlay/page.tsx +65 -30
- package/app/updates/page.js +3 -3
- package/cli.mjs +26 -15
- package/components/AdminAuth.tsx +145 -0
- package/components/AdminLinks.tsx +120 -0
- package/components/ConciergeBot.tsx +104 -44
- package/components/CountdownTimer.tsx +37 -15
- package/components/Gallery.tsx +1 -1
- package/components/LiveVideos.tsx +27 -15
- package/components/OurStory.tsx +1 -1
- package/components/SchemaMarkup.tsx +74 -0
- package/components/certificate.jsx +287 -300
- package/components/footer.tsx +2 -0
- package/components/hero.tsx +47 -4
- package/components/icons.tsx +45 -0
- package/components/importantNews.js +168 -168
- package/components/navbar.tsx +113 -18
- package/components/updates.tsx +36 -26
- package/config/firebase-admin.js +14 -17
- package/config/firebase.ts +4 -2
- package/config/site.ts +10 -2
- package/firestore.rules +6 -1
- package/next-sitemap.config.js +21 -0
- package/package.json +4 -3
- package/public/corner1-01.svg +0 -0
- package/public/love-birds.png +0 -0
- package/public/next.svg +0 -0
- package/public/pubqr.png +0 -0
- package/public/pw/sample.jpg +0 -0
- package/public/qr.png +0 -0
- package/public/sample.jpg +0 -0
- package/public/vercel.svg +0 -0
- package/vercel.json +1 -0
- package/.recover +0 -9
- package/next-env.d.ts +0 -6
- package/public/DCV.gif +0 -0
- package/public/DCV2.gif +0 -0
- package/public/DCV3.gif +0 -0
- package/public/Images/1.jpg +0 -0
- package/public/Images/11.jpg +0 -0
- package/public/Images/12.jpg +0 -0
- package/public/Images/13.jpg +0 -0
- package/public/Images/14.jpg +0 -0
- package/public/Images/15.jpg +0 -0
- package/public/Images/16.jpg +0 -0
- package/public/Images/17.jpg +0 -0
- package/public/Images/18.jpg +0 -0
- package/public/Images/19.jpg +0 -0
- package/public/Images/2.jpg +0 -0
- package/public/Images/21.jpg +0 -0
- package/public/Images/22.jpg +0 -0
- package/public/Images/3.jpg +0 -0
- package/public/Images/4.jpg +0 -0
- package/public/Images/5.jpg +0 -0
- package/public/Images/6.jpg +0 -0
- package/public/Images/7.jpg +0 -0
- package/public/Images/8.jpg +0 -0
- package/public/Images/9.jpg +0 -0
- package/public/Images/9b.jpg +0 -0
- package/public/Images/Patipatra.jpeg +0 -0
- package/public/audio (1).mp3 +0 -0
- package/public/audio (2).mp3 +0 -0
- package/public/bride.jpg +0 -0
- package/public/groom.jpg +0 -0
- package/public/invite.png +0 -0
- package/public/pw/001.jpg +0 -0
- package/public/pw/002.jpg +0 -0
- package/public/pw/003.jpg +0 -0
- package/public/pw/004.jpg +0 -0
- package/public/pw/005.jpg +0 -0
- package/public/pw/006.jpg +0 -0
- package/public/pw/007.jpg +0 -0
- package/public/pw/008.jpg +0 -0
- package/public/pw/009.jpg +0 -0
- package/public/pw/010.jpg +0 -0
- package/public/pw/011.jpg +0 -0
- package/public/pw/012.jpg +0 -0
- package/public/pw/013.jpg +0 -0
- package/public/pw/014.jpg +0 -0
- package/public/pw/015.jpg +0 -0
- package/public/pw/016.jpg +0 -0
- package/public/pw/017.jpg +0 -0
- package/public/pw/018.jpg +0 -0
- package/public/pw/019.jpg +0 -0
- package/public/pw/020.jpg +0 -0
- package/public/pw/021.jpg +0 -0
- package/public/pw/022.jpg +0 -0
- package/public/pw/023.jpg +0 -0
- package/public/pw/024.jpg +0 -0
- package/public/pw/025.jpg +0 -0
- package/public/pw/026.jpg +0 -0
- package/public/pw/027.jpg +0 -0
- package/public/pw/028.jpg +0 -0
- package/public/pw/029.jpg +0 -0
- package/public/pw/030.jpg +0 -0
- package/public/pw/031.jpg +0 -0
- package/public/pw/032.jpg +0 -0
- package/tsconfig.tsbuildinfo +0 -1
- /package/public/Images/{20.jpg → sample.jpg} +0 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
5
|
+
import { Button } from "@heroui/button";
|
|
6
|
+
|
|
7
|
+
import { HeartFilledIcon } from "@/components/icons";
|
|
8
|
+
import { title, subtitle } from "@/components/primitives";
|
|
9
|
+
|
|
10
|
+
interface Question {
|
|
11
|
+
question: string;
|
|
12
|
+
options: string[];
|
|
13
|
+
correctIndex: number;
|
|
14
|
+
fact: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const QUIZ_QUESTIONS: Question[] = [
|
|
18
|
+
{
|
|
19
|
+
question: "Where did the couple first meet?",
|
|
20
|
+
options: [
|
|
21
|
+
"In the Mountains",
|
|
22
|
+
"During College",
|
|
23
|
+
"At a Coffee Shop",
|
|
24
|
+
"At a Wedding",
|
|
25
|
+
],
|
|
26
|
+
correctIndex: 1,
|
|
27
|
+
fact: "They were college classmates before they became soulmates!",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
question: "How many years of beautiful journey have they shared so far?",
|
|
31
|
+
options: ["5 Years", "7 Years", "10 Years", "12 Years"],
|
|
32
|
+
correctIndex: 2,
|
|
33
|
+
fact: "They have shared a decade of laughter and love!",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
question: "What is one thing both of them deeply love?",
|
|
37
|
+
options: ["The Mountains", "The Ocean", "City Life", "Desert Safaris"],
|
|
38
|
+
correctIndex: 0,
|
|
39
|
+
fact: "They both share a deep love for the mountains.",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
question: "How did their story begin?",
|
|
43
|
+
options: [
|
|
44
|
+
"As Neighbors",
|
|
45
|
+
"As Colleagues",
|
|
46
|
+
"As College Classmates",
|
|
47
|
+
"Through Friends",
|
|
48
|
+
],
|
|
49
|
+
correctIndex: 2,
|
|
50
|
+
fact: "Their journey started right in the classrooms of their college.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
question: "Which of these describes their relationship perfectly?",
|
|
54
|
+
options: [
|
|
55
|
+
"Love at first sight",
|
|
56
|
+
"College classmates to soulmates",
|
|
57
|
+
"Met through a dating app",
|
|
58
|
+
"Childhood friends",
|
|
59
|
+
],
|
|
60
|
+
correctIndex: 1,
|
|
61
|
+
fact: "They truly grew together from college friends to life partners!",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
question: "What is the theme of their next chapter?",
|
|
65
|
+
options: [
|
|
66
|
+
"Starting a business",
|
|
67
|
+
"Moving to a new city",
|
|
68
|
+
"Writing a new chapter as one",
|
|
69
|
+
"Going back to college",
|
|
70
|
+
],
|
|
71
|
+
correctIndex: 2,
|
|
72
|
+
fact: "After 10 years, they are finally becoming one!",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
question: "What environment do they prefer for their adventures?",
|
|
76
|
+
options: [
|
|
77
|
+
"Tropical Beaches",
|
|
78
|
+
"Snowy Mountains",
|
|
79
|
+
"Bustling Cities",
|
|
80
|
+
"Forest Camping",
|
|
81
|
+
],
|
|
82
|
+
correctIndex: 1,
|
|
83
|
+
fact: "Their shared love for the mountains often leads them to snowy peaks!",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
question: "What brings the most laughter to their journey?",
|
|
87
|
+
options: [
|
|
88
|
+
"Watching Movies",
|
|
89
|
+
"Shared Laughter & Stories",
|
|
90
|
+
"Working together",
|
|
91
|
+
"Competitive Gaming",
|
|
92
|
+
],
|
|
93
|
+
correctIndex: 1,
|
|
94
|
+
fact: "A decade of laughter and shared stories is the foundation of their love.",
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
export default function GamePage() {
|
|
99
|
+
const [currentStep, setCurrentStep] = useState<"start" | "quiz" | "result">(
|
|
100
|
+
"start",
|
|
101
|
+
);
|
|
102
|
+
const [quizSet, setQuizSet] = useState<Question[]>([]);
|
|
103
|
+
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
|
|
104
|
+
const [score, setScore] = useState(0);
|
|
105
|
+
const [showFeedback, setShowFeedback] = useState(false);
|
|
106
|
+
const [selectedOption, setSelectedOption] = useState<number | null>(null);
|
|
107
|
+
|
|
108
|
+
const startQuiz = () => {
|
|
109
|
+
// Pick 5 random questions from the pool
|
|
110
|
+
const shuffled = [...QUIZ_QUESTIONS].sort(() => 0.5 - Math.random());
|
|
111
|
+
|
|
112
|
+
setQuizSet(shuffled.slice(0, 5));
|
|
113
|
+
|
|
114
|
+
setCurrentQuestionIndex(0);
|
|
115
|
+
setScore(0);
|
|
116
|
+
setCurrentStep("quiz");
|
|
117
|
+
setShowFeedback(false);
|
|
118
|
+
setSelectedOption(null);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleAnswer = (index: number) => {
|
|
122
|
+
if (showFeedback) return;
|
|
123
|
+
|
|
124
|
+
setSelectedOption(index);
|
|
125
|
+
if (index === quizSet[currentQuestionIndex].correctIndex) {
|
|
126
|
+
setScore((prev) => prev + 1);
|
|
127
|
+
}
|
|
128
|
+
setShowFeedback(true);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const nextQuestion = () => {
|
|
132
|
+
if (currentQuestionIndex < quizSet.length - 1) {
|
|
133
|
+
setCurrentQuestionIndex((prev) => prev + 1);
|
|
134
|
+
setShowFeedback(false);
|
|
135
|
+
setSelectedOption(null);
|
|
136
|
+
} else {
|
|
137
|
+
setCurrentStep("result");
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<section className="flex flex-col items-center justify-center gap-4 py-8 md:py-10 min-h-[70vh]">
|
|
143
|
+
<div className="inline-block max-w-lg text-center justify-center mb-8">
|
|
144
|
+
<h1 className={title({ color: "pink" })}>The Couple Quiz </h1>
|
|
145
|
+
<p className={subtitle({ className: "mt-4" })}>
|
|
146
|
+
How well do you know the couple?
|
|
147
|
+
</p>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div className="w-full max-w-xl">
|
|
151
|
+
<AnimatePresence mode="wait">
|
|
152
|
+
{currentStep === "start" && (
|
|
153
|
+
<motion.div
|
|
154
|
+
key="start"
|
|
155
|
+
animate={{ opacity: 1, y: 0 }}
|
|
156
|
+
className="flex flex-col items-center gap-6 p-8 bg-wedding-pink-50/50 dark:bg-white/5 rounded-3xl border border-wedding-pink-100 dark:border-white/10 text-center"
|
|
157
|
+
exit={{ opacity: 0, y: -20 }}
|
|
158
|
+
initial={{ opacity: 0, y: 20 }}
|
|
159
|
+
>
|
|
160
|
+
<HeartFilledIcon className="text-wedding-pink-500 w-16 h-16" />
|
|
161
|
+
<h3 className="text-2xl font-semibold">
|
|
162
|
+
Ready to test your knowledge?
|
|
163
|
+
</h3>
|
|
164
|
+
<p className="text-default-600">
|
|
165
|
+
We'll pick 5 random questions about our 10-year journey.
|
|
166
|
+
Can you get them all right?
|
|
167
|
+
</p>
|
|
168
|
+
<Button
|
|
169
|
+
className="bg-wedding-pink-500 shadow-lg px-12"
|
|
170
|
+
color="primary"
|
|
171
|
+
radius="full"
|
|
172
|
+
size="lg"
|
|
173
|
+
onClick={startQuiz}
|
|
174
|
+
>
|
|
175
|
+
Start Quiz
|
|
176
|
+
</Button>
|
|
177
|
+
</motion.div>
|
|
178
|
+
)}
|
|
179
|
+
|
|
180
|
+
{currentStep === "quiz" && quizSet.length > 0 && (
|
|
181
|
+
<motion.div
|
|
182
|
+
key="quiz"
|
|
183
|
+
animate={{ opacity: 1, x: 0 }}
|
|
184
|
+
className="flex flex-col gap-6 p-6 md:p-8 bg-white dark:bg-default-50 rounded-3xl shadow-xl border border-wedding-pink-100 dark:border-white/5"
|
|
185
|
+
exit={{ opacity: 0, x: -20 }}
|
|
186
|
+
initial={{ opacity: 0, x: 20 }}
|
|
187
|
+
>
|
|
188
|
+
<div className="flex justify-between items-center mb-2">
|
|
189
|
+
<span className="text-sm font-medium text-wedding-pink-500 uppercase tracking-widest">
|
|
190
|
+
Question {currentQuestionIndex + 1} of {quizSet.length}
|
|
191
|
+
</span>
|
|
192
|
+
<span className="text-sm text-default-400">Score: {score}</span>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<h3 className="text-xl md:text-2xl font-bold text-default-800 dark:text-default-900">
|
|
196
|
+
{quizSet[currentQuestionIndex].question}
|
|
197
|
+
</h3>
|
|
198
|
+
|
|
199
|
+
<div className="flex flex-col gap-3">
|
|
200
|
+
{quizSet[currentQuestionIndex].options.map((option, idx) => {
|
|
201
|
+
let buttonColor: "default" | "success" | "danger" = "default";
|
|
202
|
+
|
|
203
|
+
if (showFeedback) {
|
|
204
|
+
if (idx === quizSet[currentQuestionIndex].correctIndex) {
|
|
205
|
+
buttonColor = "success";
|
|
206
|
+
} else if (idx === selectedOption) {
|
|
207
|
+
buttonColor = "danger";
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<Button
|
|
213
|
+
key={idx}
|
|
214
|
+
className={`justify-start text-left h-auto py-4 px-6 text-base whitespace-normal ${
|
|
215
|
+
!showFeedback ? "hover:border-wedding-pink-400" : ""
|
|
216
|
+
}`}
|
|
217
|
+
color={buttonColor}
|
|
218
|
+
disabled={showFeedback}
|
|
219
|
+
variant={selectedOption === idx ? "solid" : "bordered"}
|
|
220
|
+
onClick={() => handleAnswer(idx)}
|
|
221
|
+
>
|
|
222
|
+
{option}
|
|
223
|
+
</Button>
|
|
224
|
+
);
|
|
225
|
+
})}
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
{showFeedback && (
|
|
229
|
+
<motion.div
|
|
230
|
+
animate={{ opacity: 1, height: "auto" }}
|
|
231
|
+
className="mt-4 p-4 bg-default-100 rounded-2xl"
|
|
232
|
+
initial={{ opacity: 0, height: 0 }}
|
|
233
|
+
>
|
|
234
|
+
<p className="text-sm italic text-default-700">
|
|
235
|
+
<span className="font-bold mr-2">Did you know?</span>
|
|
236
|
+
{quizSet[currentQuestionIndex].fact}
|
|
237
|
+
</p>
|
|
238
|
+
<Button
|
|
239
|
+
className="mt-4 w-full bg-wedding-pink-500 text-white shadow-md"
|
|
240
|
+
onClick={nextQuestion}
|
|
241
|
+
>
|
|
242
|
+
{currentQuestionIndex < quizSet.length - 1
|
|
243
|
+
? "Next Question"
|
|
244
|
+
: "See Results"}
|
|
245
|
+
</Button>
|
|
246
|
+
</motion.div>
|
|
247
|
+
)}
|
|
248
|
+
</motion.div>
|
|
249
|
+
)}
|
|
250
|
+
|
|
251
|
+
{currentStep === "result" && (
|
|
252
|
+
<motion.div
|
|
253
|
+
key="result"
|
|
254
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
255
|
+
className="flex flex-col items-center gap-6 p-8 bg-wedding-gold-50/50 dark:bg-white/5 rounded-3xl border border-wedding-gold-100 dark:border-white/10 text-center"
|
|
256
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
257
|
+
>
|
|
258
|
+
<div className="relative">
|
|
259
|
+
<HeartFilledIcon className="text-wedding-pink-500 w-20 h-20" />
|
|
260
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
261
|
+
<span className="text-white font-bold text-xl">{score}</span>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<h3 className="text-3xl font-bold">
|
|
266
|
+
{score === quizSet.length
|
|
267
|
+
? "True Soulmate Friend!"
|
|
268
|
+
: score >= 3
|
|
269
|
+
? "Great Job!"
|
|
270
|
+
: "Thanks for Playing!"}
|
|
271
|
+
</h3>
|
|
272
|
+
|
|
273
|
+
<p className="text-lg text-default-600">
|
|
274
|
+
You scored{" "}
|
|
275
|
+
<span className="text-wedding-pink-600 font-bold">{score}</span>{" "}
|
|
276
|
+
out of {quizSet.length}
|
|
277
|
+
</p>
|
|
278
|
+
|
|
279
|
+
<div className="flex gap-4 w-full">
|
|
280
|
+
<Button className="flex-1" variant="flat" onClick={startQuiz}>
|
|
281
|
+
Play Again
|
|
282
|
+
</Button>
|
|
283
|
+
<Button
|
|
284
|
+
as="a"
|
|
285
|
+
className="flex-1 bg-wedding-gold-600"
|
|
286
|
+
color="primary"
|
|
287
|
+
href="/"
|
|
288
|
+
>
|
|
289
|
+
Back Home
|
|
290
|
+
</Button>
|
|
291
|
+
</div>
|
|
292
|
+
</motion.div>
|
|
293
|
+
)}
|
|
294
|
+
</AnimatePresence>
|
|
295
|
+
</div>
|
|
296
|
+
</section>
|
|
297
|
+
);
|
|
298
|
+
}
|