@titas_mallick/wedding-site-gen 1.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.
Files changed (141) hide show
  1. package/.eslintignore +20 -0
  2. package/.eslintrc.json +93 -0
  3. package/.recover +9 -0
  4. package/.vscode/settings.json +3 -0
  5. package/LICENSE +21 -0
  6. package/README.md +83 -0
  7. package/app/Neo-Lucentism/layout.tsx +7 -0
  8. package/app/Neo-Lucentism/page.tsx +259 -0
  9. package/app/couple/layout.tsx +7 -0
  10. package/app/couple/page.tsx +164 -0
  11. package/app/error.tsx +31 -0
  12. package/app/guestbook/page.tsx +470 -0
  13. package/app/invitation/[slug]/layout.tsx +36 -0
  14. package/app/invitation/[slug]/page.tsx +462 -0
  15. package/app/invitation/maker/auth.js +165 -0
  16. package/app/invitation/maker/dashboard.js +81 -0
  17. package/app/invitation/maker/guestAdder.js +204 -0
  18. package/app/invitation/maker/guestShower.js +287 -0
  19. package/app/invitation/maker/layout.tsx +11 -0
  20. package/app/invitation/maker/page.js +168 -0
  21. package/app/invitation/maker/rsvpViewer.js +122 -0
  22. package/app/layout.tsx +98 -0
  23. package/app/mark-the-dates/layout.tsx +7 -0
  24. package/app/mark-the-dates/page.tsx +196 -0
  25. package/app/memories/layout.tsx +7 -0
  26. package/app/memories/page.tsx +29 -0
  27. package/app/page.tsx +5 -0
  28. package/app/providers.tsx +33 -0
  29. package/app/sagun/layout.tsx +7 -0
  30. package/app/sagun/page.tsx +348 -0
  31. package/app/song-requests/page.tsx +354 -0
  32. package/app/sukanya/layout.tsx +7 -0
  33. package/app/sukanya/page.tsx +167 -0
  34. package/app/titas/layout.tsx +7 -0
  35. package/app/titas/page.tsx +175 -0
  36. package/app/travel-guide/page.tsx +400 -0
  37. package/app/updates/maker/page.js +323 -0
  38. package/app/updates/overlay/page.tsx +144 -0
  39. package/app/updates/page.js +207 -0
  40. package/cli.mjs +196 -0
  41. package/components/ConciergeBot.tsx +203 -0
  42. package/components/CountdownTimer.tsx +137 -0
  43. package/components/Gallery.tsx +372 -0
  44. package/components/LiveVideos.tsx +173 -0
  45. package/components/OurStory.tsx +160 -0
  46. package/components/certificate.jsx +300 -0
  47. package/components/counter.tsx +14 -0
  48. package/components/footer.tsx +89 -0
  49. package/components/hero.tsx +136 -0
  50. package/components/icons.tsx +283 -0
  51. package/components/importantNews.js +168 -0
  52. package/components/navbar.tsx +106 -0
  53. package/components/primitives.ts +53 -0
  54. package/components/sagun.js +22 -0
  55. package/components/theme-switch.tsx +81 -0
  56. package/components/updates.tsx +118 -0
  57. package/components/weddingcard.js +68 -0
  58. package/components/weddingcard2.js +58 -0
  59. package/config/firebase-admin.js +17 -0
  60. package/config/firebase.ts +36 -0
  61. package/config/fonts.ts +21 -0
  62. package/config/site.ts +74 -0
  63. package/next-env.d.ts +6 -0
  64. package/next.config.js +4 -0
  65. package/package.json +64 -0
  66. package/postcss.config.js +6 -0
  67. package/public/DCV.gif +0 -0
  68. package/public/DCV2.gif +0 -0
  69. package/public/DCV3.gif +0 -0
  70. package/public/Images/1.jpg +0 -0
  71. package/public/Images/11.jpg +0 -0
  72. package/public/Images/12.jpg +0 -0
  73. package/public/Images/13.jpg +0 -0
  74. package/public/Images/14.jpg +0 -0
  75. package/public/Images/15.jpg +0 -0
  76. package/public/Images/16.jpg +0 -0
  77. package/public/Images/17.jpg +0 -0
  78. package/public/Images/18.jpg +0 -0
  79. package/public/Images/19.jpg +0 -0
  80. package/public/Images/2.jpg +0 -0
  81. package/public/Images/20.jpg +0 -0
  82. package/public/Images/21.jpg +0 -0
  83. package/public/Images/22.jpg +0 -0
  84. package/public/Images/3.jpg +0 -0
  85. package/public/Images/4.jpg +0 -0
  86. package/public/Images/5.jpg +0 -0
  87. package/public/Images/6.jpg +0 -0
  88. package/public/Images/7.jpg +0 -0
  89. package/public/Images/8.jpg +0 -0
  90. package/public/Images/9.jpg +0 -0
  91. package/public/Images/9b.jpg +0 -0
  92. package/public/Images/Patipatra.jpeg +0 -0
  93. package/public/audio (1).mp3 +0 -0
  94. package/public/audio (2).mp3 +0 -0
  95. package/public/bride.jpg +0 -0
  96. package/public/corner1-01.svg +1 -0
  97. package/public/favicon.ico +0 -0
  98. package/public/groom.jpg +0 -0
  99. package/public/invite.png +0 -0
  100. package/public/love-birds.png +0 -0
  101. package/public/next.svg +1 -0
  102. package/public/pubqr.png +0 -0
  103. package/public/pw/001.jpg +0 -0
  104. package/public/pw/002.jpg +0 -0
  105. package/public/pw/003.jpg +0 -0
  106. package/public/pw/004.jpg +0 -0
  107. package/public/pw/005.jpg +0 -0
  108. package/public/pw/006.jpg +0 -0
  109. package/public/pw/007.jpg +0 -0
  110. package/public/pw/008.jpg +0 -0
  111. package/public/pw/009.jpg +0 -0
  112. package/public/pw/010.jpg +0 -0
  113. package/public/pw/011.jpg +0 -0
  114. package/public/pw/012.jpg +0 -0
  115. package/public/pw/013.jpg +0 -0
  116. package/public/pw/014.jpg +0 -0
  117. package/public/pw/015.jpg +0 -0
  118. package/public/pw/016.jpg +0 -0
  119. package/public/pw/017.jpg +0 -0
  120. package/public/pw/018.jpg +0 -0
  121. package/public/pw/019.jpg +0 -0
  122. package/public/pw/020.jpg +0 -0
  123. package/public/pw/021.jpg +0 -0
  124. package/public/pw/022.jpg +0 -0
  125. package/public/pw/023.jpg +0 -0
  126. package/public/pw/024.jpg +0 -0
  127. package/public/pw/025.jpg +0 -0
  128. package/public/pw/026.jpg +0 -0
  129. package/public/pw/027.jpg +0 -0
  130. package/public/pw/028.jpg +0 -0
  131. package/public/pw/029.jpg +0 -0
  132. package/public/pw/030.jpg +0 -0
  133. package/public/pw/031.jpg +0 -0
  134. package/public/pw/032.jpg +0 -0
  135. package/public/qr.png +0 -0
  136. package/public/vercel.svg +1 -0
  137. package/styles/globals.css +3 -0
  138. package/tailwind.config.js +51 -0
  139. package/tsconfig.json +45 -0
  140. package/tsconfig.tsbuildinfo +1 -0
  141. package/types/index.ts +5 -0
@@ -0,0 +1,81 @@
1
+ "use client";
2
+
3
+ import { Card, CardHeader, CardBody } from "@heroui/react";
4
+
5
+ const Dash = ({ guests }) => {
6
+ const stats = {
7
+ reception: { bride: 0, groom: 0, total: 0 },
8
+ wedding: { bride: 0, groom: 0, total: 0 },
9
+ registration: { bride: 0, groom: 0, total: 0 },
10
+ rsvpStatus: { accepted: 0, pending: 0, declined: 0, total: guests.length },
11
+ };
12
+
13
+ guests.forEach((guest) => {
14
+ const side = guest.familySide === "groom" ? "groom" : "bride";
15
+ const count = guest.invitedGuests || 1;
16
+
17
+ guest.invitedFor.forEach((event) => {
18
+ if (stats[event]) {
19
+ stats[event][side] += count;
20
+ stats[event].total += count;
21
+ }
22
+ });
23
+
24
+ const rsvp = guest.rsvpStatus?.toLowerCase();
25
+ if (rsvp === "accepted") stats.rsvpStatus.accepted += 1;
26
+ else if (rsvp === "pending") stats.rsvpStatus.pending += 1;
27
+ else if (rsvp === "declined") stats.rsvpStatus.declined += 1;
28
+ });
29
+
30
+ const eventCards = [
31
+ { title: "Reception", data: stats.reception },
32
+ { title: "Wedding", data: stats.wedding },
33
+ { title: "Registration", data: stats.registration },
34
+ ];
35
+
36
+ return (
37
+ <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 p-4">
38
+ {eventCards.map((event, idx) => (
39
+ <Card key={idx} shadow="none" className="rounded-xl">
40
+ <CardHeader>
41
+ <h3 className="text-lg font-semibold">{event.title}</h3>
42
+ </CardHeader>
43
+ <CardBody className="space-y-1 text-sm ">
44
+ <p>Bride Side: {event.data.bride}</p>
45
+ <p>Groom Side: {event.data.groom}</p>
46
+ <p>Total: {event.data.total}</p>
47
+ </CardBody>
48
+ </Card>
49
+ ))}
50
+
51
+ <Card
52
+ shadow="none"
53
+ className="rounded-xl md:col-span-2 xl:col-span-3"
54
+ >
55
+ <CardHeader>
56
+ <h3 className="text-lg font-semibold">RSVP Summary</h3>
57
+ </CardHeader>
58
+ <CardBody className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm ">
59
+ <div>
60
+ <p>Accepted:</p>
61
+ <p className="font-medium">{stats.rsvpStatus.accepted}</p>
62
+ </div>
63
+ <div>
64
+ <p>Pending:</p>
65
+ <p className="font-medium">{stats.rsvpStatus.pending}</p>
66
+ </div>
67
+ <div>
68
+ <p>Declined:</p>
69
+ <p className="font-medium">{stats.rsvpStatus.declined}</p>
70
+ </div>
71
+ <div>
72
+ <p>Total Names:</p>
73
+ <p className="font-medium">{stats.rsvpStatus.total}</p>
74
+ </div>
75
+ </CardBody>
76
+ </Card>
77
+ </div>
78
+ );
79
+ };
80
+
81
+ export default Dash;
@@ -0,0 +1,204 @@
1
+ "use client";
2
+
3
+ import React, { useState, useEffect } from "react";
4
+ import {
5
+ Modal,
6
+ ModalContent,
7
+ ModalHeader,
8
+ ModalBody,
9
+ ModalFooter,
10
+ Button,
11
+ Input,
12
+ Textarea,
13
+ RadioGroup,
14
+ Radio,
15
+ CheckboxGroup,
16
+ Checkbox,
17
+ } from "@heroui/react";
18
+ import { fontSans, fontMono } from "@/config/fonts";
19
+
20
+ const defaultForm = {
21
+ name: "",
22
+ contact: "",
23
+ familySide: "",
24
+ relation: "",
25
+ invitedFor: [],
26
+ invitedGuests: "1",
27
+ rsvpStatus: "pending",
28
+ notes: "",
29
+ };
30
+
31
+ export default function AddGuestModal({
32
+ isOpen,
33
+ onClose,
34
+ onAdd, // only onAdd, no onUpdate
35
+ existingGuest,
36
+ }) {
37
+ const [formData, setFormData] = useState(defaultForm);
38
+
39
+ useEffect(() => {
40
+ if (existingGuest) {
41
+ setFormData(existingGuest);
42
+ } else {
43
+ setFormData(defaultForm);
44
+ }
45
+ }, [existingGuest]);
46
+
47
+ const handleChange = (e) => {
48
+ setFormData({ ...formData, [e.target.name]: e.target.value });
49
+ };
50
+
51
+ const handleRadioChange = (key, value) => {
52
+ setFormData({ ...formData, [key]: value });
53
+ };
54
+
55
+ const handleCheckboxChange = (key, values) => {
56
+ setFormData({ ...formData, [key]: values });
57
+ };
58
+
59
+ const handleSubmit = (e) => {
60
+ e.preventDefault();
61
+ onAdd(formData); // always call onAdd for both add & update
62
+ onClose();
63
+ setFormData(defaultForm);
64
+ };
65
+
66
+ return (
67
+ <Modal
68
+ isOpen={isOpen}
69
+ onOpenChange={onClose}
70
+ backdrop="blur"
71
+ scrollBehavior="outside"
72
+ >
73
+ <ModalContent className="max-w-lg w-full">
74
+ {(close) => (
75
+ <form
76
+ onSubmit={(e) => {
77
+ handleSubmit(e);
78
+ close();
79
+ }}
80
+ className={`${fontSans.className} border-none outline-none`}
81
+ >
82
+ <ModalHeader className="text-2xl">
83
+ {existingGuest ? "Update Guest" : "Add New Guest"}
84
+ </ModalHeader>
85
+ <ModalBody>
86
+ <Input
87
+ isRequired
88
+ label="Guest Name"
89
+ placeholder="Enter guest name"
90
+ name="name"
91
+ value={formData.name}
92
+ onChange={handleChange}
93
+ variant="bordered"
94
+ labelPlacement="outside-top"
95
+ size="lg"
96
+ classNames={{
97
+ input: "outline-none",
98
+ }}
99
+ />
100
+ <Input
101
+ label="Contact Info"
102
+ placeholder="Enter phone or email"
103
+ name="contact"
104
+ value={formData.contact}
105
+ onChange={handleChange}
106
+ variant="bordered"
107
+ size="lg"
108
+ labelPlacement="outside-top"
109
+ classNames={{
110
+ input: "outline-none",
111
+ }}
112
+ />
113
+
114
+ <RadioGroup
115
+ isRequired
116
+ label="Family Side"
117
+ orientation="horizontal"
118
+ value={formData.familySide}
119
+ onValueChange={(val) => handleRadioChange("familySide", val)}
120
+ >
121
+ <Radio value="bride">Bride&apos;s Side</Radio>
122
+ <Radio value="groom">Groom&apos;s Side</Radio>
123
+ </RadioGroup>
124
+
125
+ <RadioGroup
126
+ isRequired
127
+ label="Relation to Couple"
128
+ orientation="horizontal"
129
+ value={formData.relation}
130
+ onValueChange={(val) => handleRadioChange("relation", val)}
131
+ >
132
+ <Radio value="family">Family</Radio>
133
+ <Radio value="colleague">Colleague</Radio>
134
+ <Radio value="friend">Friend</Radio>
135
+ <Radio value="other">Other</Radio>
136
+ </RadioGroup>
137
+
138
+ <CheckboxGroup
139
+ label="Invited For"
140
+ orientation="horizontal"
141
+ value={formData.invitedFor}
142
+ onValueChange={(val) => handleCheckboxChange("invitedFor", val)}
143
+ isRequired
144
+ >
145
+ <Checkbox value="registration">Registration</Checkbox>
146
+ <Checkbox value="wedding">Wedding</Checkbox>
147
+ <Checkbox value="reception">Reception</Checkbox>
148
+ </CheckboxGroup>
149
+
150
+ <Input
151
+ type="number"
152
+ label="Total Guests"
153
+ labelPlacement="outside-top"
154
+ placeholder="1"
155
+ name="invitedGuests"
156
+ min={1}
157
+ value={formData.invitedGuests}
158
+ onChange={handleChange}
159
+ variant="bordered"
160
+ size="lg"
161
+ classNames={{
162
+ input: "outline-none",
163
+ }}
164
+ />
165
+
166
+ <RadioGroup
167
+ label="RSVP Status"
168
+ orientation="horizontal"
169
+ value={formData.rsvpStatus}
170
+ onValueChange={(val) => handleRadioChange("rsvpStatus", val)}
171
+ >
172
+ <Radio value="pending">Pending</Radio>
173
+ <Radio value="accepted">Accepted</Radio>
174
+ <Radio value="declined">Declined</Radio>
175
+ <Radio value="maybe">Maybe</Radio>
176
+ </RadioGroup>
177
+
178
+ <Textarea
179
+ label="Notes (Optional)"
180
+ placeholder="Enter any special notes"
181
+ name="notes"
182
+ value={formData.notes}
183
+ onChange={handleChange}
184
+ variant="bordered"
185
+ size="lg"
186
+ classNames={{
187
+ input: "outline-none",
188
+ }}
189
+ />
190
+ </ModalBody>
191
+ <ModalFooter>
192
+ <Button variant="light" onPress={onClose}>
193
+ Cancel
194
+ </Button>
195
+ <Button color="primary" type="submit">
196
+ {existingGuest ? "Update Guest" : "Save Guest"}
197
+ </Button>
198
+ </ModalFooter>
199
+ </form>
200
+ )}
201
+ </ModalContent>
202
+ </Modal>
203
+ );
204
+ }
@@ -0,0 +1,287 @@
1
+ "use client";
2
+
3
+ import {
4
+ Chip,
5
+ Button,
6
+ Select,
7
+ SelectItem,
8
+ Card,
9
+ CardBody,
10
+ CardHeader,
11
+ CardFooter,
12
+ Link,
13
+ } from "@heroui/react";
14
+ import { fontSans, fontMono } from "@/config/fonts";
15
+ import { useState, useMemo } from "react";
16
+
17
+ const familyChipColor = {
18
+ bride: "primary",
19
+ groom: "secondary",
20
+ };
21
+
22
+ const rsvpChipColor = {
23
+ accepted: "success",
24
+ declined: "danger",
25
+ maybe: "warning",
26
+ pending: "default",
27
+ };
28
+
29
+ const rsvpBorderColor = {
30
+ accepted: "border-success",
31
+ declined: "border-danger",
32
+ maybe: "border-warning",
33
+ pending: "border-default",
34
+ };
35
+
36
+ const invitedForColor = {
37
+ registration: "success",
38
+ reception: "danger",
39
+ wedding: "warning",
40
+ };
41
+
42
+ export default function GuestTable({ guests, onEdit, onDelete, onAdd }) {
43
+ const [filters, setFilters] = useState({
44
+ familySide: "all",
45
+ invitedFor: "all",
46
+ relation: "all",
47
+ rsvpStatus: "all",
48
+ });
49
+
50
+ const handleFilterChange = (key, value) => {
51
+ setFilters((prev) => ({
52
+ ...prev,
53
+ [key]: value,
54
+ }));
55
+ };
56
+
57
+ const filteredGuests = useMemo(() => {
58
+ return guests.filter((guest) => {
59
+ if (
60
+ filters.familySide !== "all" &&
61
+ guest.familySide !== filters.familySide
62
+ )
63
+ return false;
64
+ if (
65
+ filters.invitedFor !== "all" &&
66
+ !guest.invitedFor.includes(filters.invitedFor)
67
+ )
68
+ return false;
69
+ if (filters.relation !== "all" && guest.relation !== filters.relation)
70
+ return false;
71
+ if (
72
+ filters.rsvpStatus !== "all" &&
73
+ guest.rsvpStatus !== filters.rsvpStatus
74
+ )
75
+ return false;
76
+ return true;
77
+ });
78
+ }, [guests, filters]);
79
+
80
+ return (
81
+ <div className={`${fontSans.className}`}>
82
+ {/* FILTER SECTION */}
83
+ <Card className="mb-4 w-full shadow-sm bg-transparent">
84
+ <CardBody className="p-2 flex flex-col gap-4 sm:flex-row sm:justify-between sm:items-center">
85
+ <Button onPress={onAdd} color="primary" className="w-full sm:w-auto">
86
+ Add Guest
87
+ </Button>
88
+
89
+ <div className="flex flex-wrap gap-3 w-full sm:w-auto justify-start sm:justify-end">
90
+ <Select
91
+ label="Family Side"
92
+ variant="bordered"
93
+ size="sm"
94
+ labelPlacement="inside"
95
+ className="min-w-[140px] max-w-[160px] flex-1 [&_label]:!pb-1.5 [&_[data-slot=value]]:!pt-1.5"
96
+ selectedKeys={[filters.familySide]}
97
+ onSelectionChange={(e) =>
98
+ handleFilterChange("familySide", Array.from(e)[0])
99
+ }
100
+ >
101
+ <SelectItem key="all">All</SelectItem>
102
+ <SelectItem key="bride">Bride</SelectItem>
103
+ <SelectItem key="groom">Groom</SelectItem>
104
+ </Select>
105
+
106
+ <Select
107
+ label="Invited For"
108
+ variant="bordered"
109
+ size="sm"
110
+ labelPlacement="inside"
111
+ className="min-w-[140px] max-w-[160px] flex-1 [&_label]:!pb-1.5 [&_[data-slot=value]]:!pt-1.5"
112
+ selectedKeys={[filters.invitedFor]}
113
+ onSelectionChange={(e) =>
114
+ handleFilterChange("invitedFor", Array.from(e)[0])
115
+ }
116
+ >
117
+ <SelectItem key="all">All</SelectItem>
118
+ <SelectItem key="registration">Registration</SelectItem>
119
+ <SelectItem key="wedding">Wedding</SelectItem>
120
+ <SelectItem key="reception">Reception</SelectItem>
121
+ </Select>
122
+
123
+ <Select
124
+ label="Relation"
125
+ variant="bordered"
126
+ size="sm"
127
+ labelPlacement="inside"
128
+ className="min-w-[140px] max-w-[160px] flex-1 [&_label]:!pb-1.5 [&_[data-slot=value]]:!pt-1.5"
129
+ selectedKeys={[filters.relation]}
130
+ onSelectionChange={(e) =>
131
+ handleFilterChange("relation", Array.from(e)[0])
132
+ }
133
+ >
134
+ <SelectItem key="all">All</SelectItem>
135
+ <SelectItem key="friend">Friend</SelectItem>
136
+ <SelectItem key="family">Family</SelectItem>
137
+ <SelectItem key="colleague">Colleague</SelectItem>
138
+ <SelectItem key="other">Other</SelectItem>
139
+ </Select>
140
+
141
+ <Select
142
+ label="RSVP"
143
+ variant="bordered"
144
+ size="sm"
145
+ labelPlacement="inside"
146
+ className="min-w-[140px] max-w-[160px] flex-1 [&_label]:!pb-1.5 [&_[data-slot=value]]:!pt-1.5"
147
+ selectedKeys={[filters.rsvpStatus]}
148
+ onSelectionChange={(e) =>
149
+ handleFilterChange("rsvpStatus", Array.from(e)[0])
150
+ }
151
+ >
152
+ <SelectItem key="all">All</SelectItem>
153
+ <SelectItem key="accepted">Accepted</SelectItem>
154
+ <SelectItem key="declined">Declined</SelectItem>
155
+ <SelectItem key="maybe">Maybe</SelectItem>
156
+ <SelectItem key="pending">Pending</SelectItem>
157
+ </Select>
158
+ </div>
159
+ </CardBody>
160
+ </Card>
161
+
162
+ {/* CARD VIEW (ALL SCREENS) */}
163
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 w-full">
164
+ {filteredGuests.map((guest, index) => (
165
+ <Card
166
+ key={index}
167
+ className={`flex text-left flex-col justify-between mb-2 border-t-4 ${rsvpBorderColor[guest.rsvpStatus]} shadow-md h-full`}
168
+ >
169
+ <CardHeader className="flex justify-between items-center px-4 pt-4 pb-2">
170
+ <div>
171
+ <p className="font-bold text-base">{guest.name}</p>
172
+ <p className="text-sm capitalize">
173
+ {guest.relation} •{" "}
174
+ <span className="capitalize">{guest.familySide}</span>
175
+ </p>
176
+ </div>
177
+ <Chip
178
+ size="sm"
179
+ color={familyChipColor[guest.familySide]}
180
+ variant="flat"
181
+ className="capitalize"
182
+ >
183
+ {guest.familySide}
184
+ </Chip>
185
+ </CardHeader>
186
+
187
+ <CardBody className="px-4 py-2 space-y-2 text-sm grow">
188
+ <p>
189
+ <strong>Contact:</strong>{" "}
190
+ {guest.contact?.length >= 2
191
+ ? `${guest.contact.charAt(0)}${"*".repeat(
192
+ guest.contact.length - 2
193
+ )}${guest.contact.charAt(guest.contact.length - 1)}`
194
+ : guest.contact}
195
+ </p>
196
+ <section>
197
+ <strong>Invited For:</strong>
198
+ <div className="flex flex-wrap gap-1 mt-1">
199
+ {guest.invitedFor.map((item, i) => (
200
+ <Chip
201
+ key={i}
202
+ variant="flat"
203
+ size="sm"
204
+ color={invitedForColor[item.toLowerCase()]}
205
+ className={fontMono.className}
206
+ >
207
+ {item}
208
+ </Chip>
209
+ ))}
210
+ </div>
211
+ </section>
212
+ <p>
213
+ <strong>Guests Count:</strong> {guest.invitedGuests}
214
+ </p>
215
+ {guest.notes && (
216
+ <p>
217
+ <strong>Notes:</strong> {guest.notes}
218
+ </p>
219
+ )}
220
+ <div className="flex flex-wrap gap-1 mt-2">
221
+ <Link
222
+ color="foreground"
223
+ showAnchorIcon
224
+ href={`./${guest.id}`}
225
+ className="bg-yellow-500 text-black dark:text-white px-3 py-1 rounded hover:bg-yellow-700"
226
+ >
227
+ invitation
228
+ </Link>
229
+ <button
230
+ onClick={() => {
231
+ if (navigator.share) {
232
+ navigator
233
+ .share({
234
+ title: "Wedding Invitation",
235
+ text: `Join us! Here’s your invitation link:`,
236
+ url: `${window.location.origin}/invitation/${guest.id}`,
237
+ })
238
+ .catch((error) =>
239
+ console.error("Error sharing", error)
240
+ );
241
+ } else {
242
+ alert("Sharing is not supported in this browser.");
243
+ }
244
+ }}
245
+ className="bg-blue-600 text-white px-3 py-1 rounded hover:bg-blue-700"
246
+ >
247
+ Share
248
+ </button>
249
+ {guest.contact && (
250
+ <a
251
+ href={`https://wa.me/${guest.contact.replace(/[^0-9]/g, "")}?text=${encodeURIComponent(
252
+ `Hi! You are invited to Titas & Sukanya's wedding. Here's your invitation link: ${window.location.origin}/${guest.id}`
253
+ )}`}
254
+ target="_blank"
255
+ rel="noopener noreferrer"
256
+ className="bg-green-600 text-white px-3 py-1 rounded hover:bg-green-700"
257
+ >
258
+ WhatsApp
259
+ </a>
260
+ )}
261
+ </div>
262
+ </CardBody>
263
+
264
+ <CardFooter className="flex justify-end gap-2 px-4 pb-4 pt-2">
265
+ <Button
266
+ size="sm"
267
+ variant="bordered"
268
+ color="primary"
269
+ onPress={() => onEdit(guest)}
270
+ >
271
+ Edit
272
+ </Button>
273
+ <Button
274
+ size="sm"
275
+ variant="bordered"
276
+ color="danger"
277
+ onPress={() => onDelete(guest)}
278
+ >
279
+ Delete
280
+ </Button>
281
+ </CardFooter>
282
+ </Card>
283
+ ))}
284
+ </div>
285
+ </div>
286
+ );
287
+ }
@@ -0,0 +1,11 @@
1
+ export default function PricingLayout({
2
+ children,
3
+ }: {
4
+ children: React.ReactNode;
5
+ }) {
6
+ return (
7
+ <section className="flex flex-col items-center justify-center gap-4 md:px-20 py-8 md:py-10">
8
+ <div className="inline-block text-center justify-center">{children}</div>
9
+ </section>
10
+ );
11
+ }