1import { useContext, useMemo, useRef, useState } from "react";
2import { useParams } from "react-router";
3import { QRCodeCanvas } from "qrcode.react";
4
5import PageTitle from "@/components/page-title";
6import GoBack from "@/components/goback";
7
8import { AppContext } from "@/ContextProvider";
9import { formatDate, logger } from "@/utils";
10
11const ActivityShare = () => {
12 const params = useParams();
13 const whatsappLinkRef = useRef(null);
14 const qrCodeRef = useRef(null);
15
16 const [copyStatus, setCopyStatus] = useState("");
17
18 const { state } = useContext(AppContext);
19 const upiId = state.upiSettings.id || "";
20 const upiName = state.upiSettings.name || "";
21
22 const activity = state.activities.find((a) => a.id === params.id);
23
24 let upiLink = `upi://pay?pa=${upiId}&am=${
25 activity.splitPerPerson
26 }.00&cu=INR&tn=${encodeURIComponent(activity.title)}`;
27 if (upiName) {
28 upiLink += `&pn=${encodeURIComponent(upiName)}`;
29 }
30
31 const shareMessage = useMemo(() => {
32 const data = {
33 text: "",
34 encoded: "",
35 whatsappLink: "https://api.whatsapp.com/send?text=",
36 };
37
38 if (!activity) {
39 return data;
40 }
41
42 data.text += `Hiyya,\n\n`;
43 data.text += `Split for ${activity.title} is Rs.${activity.splitPerPerson}\n\n`;
44 data.text += `Items\n`;
45 for (let i = 0; i < activity.itemSpends.length; i++) {
46 const item = activity.itemSpends[i];
47 data.text += ` ${i + 1}. ${item["title"]} ${item["amount"]}\n`;
48 }
49 data.text += "\n";
50 data.text += `Total: Rs.${activity.totalAmount}\n`;
51 data.text += "\n";
52
53 for (let i = 0; i < activity.friends.length; i++) {
54 const friend = activity.friends[i];
55 data.text += ` ${i + 1}. ${friend["name"]}\n`;
56 }
57 data.text += "\n";
58
59 data.text += "To pay, please scan the below QR code.\n";
60 data.text += "\n";
61
62 // will be using QR code for now.
63 // links are makred insecure by google pay and phonepe
64 // data.text += `Pay via UPI:\n${upiLink}`;
65
66 data.encoded = encodeURIComponent(data.text)
67 .replace(/'/g, "%27")
68 .replace(/"/g, "%22");
69
70 data.whatsappLink += data.encoded;
71
72 return data;
73 }, [
74 activity,
75 // upiLink
76 ]);
77
78 const handleCopyQRCode = async () => {
79 if (!qrCodeRef.current) {
80 return;
81 }
82
83 const qrCodeCanvas = qrCodeRef.current;
84 try {
85 qrCodeCanvas.toBlob(async (blob) => {
86 if (!blob) {
87 logger("Failed to create blob.");
88 setCopyStatus("failed");
89 return;
90 }
91
92 const item = new ClipboardItem({ [blob.type]: blob });
93 await navigator.clipboard.write([item]);
94 setCopyStatus("copied!");
95 setTimeout(() => setCopyStatus(""), 3000);
96 }, "image/png");
97 } catch (error) {
98 logger("Error copying canvas:", error);
99 setCopyStatus("denied");
100 }
101 };
102
103 const handleWhatsAppShareClick = async () => {
104 if (!whatsappLinkRef.current) {
105 return;
106 }
107 whatsappLinkRef.current.click();
108 return;
109 };
110
111 if (!activity) {
112 return (
113 <>
114 <GoBack />
115 <PageTitle title="activity not found" />
116
117 <h1>activity not found</h1>
118 </>
119 );
120 }
121
122 return (
123 <>
124 <GoBack />
125 <PageTitle title={`share ${activity.title}`} />
126
127 <h1 className="h6">
128 <span className="muted small">share</span> {activity.title}
129 </h1>
130
131 <div style={{ marginTop: "10px" }}>
132 <p style={{ margin: "0px", padding: "0px", fontWeight: "bold" }}>
133 {activity.title}
134 </p>
135 <p style={{ margin: "0px", padding: "0px" }} className="muted">
136 <small>{formatDate(activity.createdAt)}</small>
137 </p>
138
139 <table
140 className="table"
141 style={{ fontSize: "0.8rem", width: "100%", marginTop: "5px" }}
142 >
143 <thead>
144 <tr>
145 <th>#</th>
146 <th>item / spend</th>
147 <th>₹</th>
148 </tr>
149 </thead>
150 <tbody>
151 {activity.itemSpends.map((i, idx) => (
152 <tr key={i.id}>
153 <td>{idx + 1}</td>
154 <td>{i.title}</td>
155 <td style={{ fontFamily: "monospace" }}>{i.amount}</td>
156 </tr>
157 ))}
158
159 <tr>
160 <td></td>
161 <td style={{ fontWeight: "bold" }}>Total</td>
162 <td style={{ fontFamily: "monospace" }}>
163 {activity.totalAmount}
164 </td>
165 </tr>
166 </tbody>
167 </table>
168
169 <br />
170
171 <table
172 className="table"
173 style={{ fontSize: "0.8rem", width: "100%", marginTop: "5px" }}
174 >
175 <thead>
176 <tr>
177 <th>#</th>
178 <th>friend</th>
179 <th>₹</th>
180 </tr>
181 </thead>
182
183 <tbody>
184 {activity.friends.map((f, idx) => (
185 <tr key={f.id}>
186 <td>{idx + 1}</td>
187 <td>{f.name}</td>
188 <td style={{ fontFamily: "monospace" }}>
189 {activity.splitPerPerson}
190 </td>
191 </tr>
192 ))}
193 <tr>
194 <td>{activity.friends.length + 1}</td>
195 <td>me</td>
196 <td style={{ fontFamily: "monospace" }}>
197 {activity.splitPerPerson}
198 </td>
199 </tr>
200 </tbody>
201 </table>
202 </div>
203
204 <div style={{ marginTop: "10px", fontSize: "0.8rem" }}>
205 <details>
206 <summary style={{ padding: "3px" }} className="cursor-pointer">
207 message
208 </summary>
209 <div>
210 <textarea
211 value={shareMessage.text}
212 readOnly
213 rows={10}
214 style={{ fontSize: "0.8rem" }}
215 ></textarea>
216 </div>
217 </details>
218 </div>
219
220 <textarea className="d-none" value={upiLink} readOnly></textarea>
221 <div className="text-center" style={{ marginTop: "10px" }}>
222 <QRCodeCanvas
223 marginSize={4}
224 title={upiId}
225 value={upiLink}
226 ref={qrCodeRef}
227 />
228 </div>
229
230 <div className="text-center" style={{ marginTop: "8px" }}>
231 <button className="btn btn-b" onClick={handleCopyQRCode}>
232 {copyStatus === "" ? "copy QR code" : copyStatus}
233 </button>
234 </div>
235
236 <a
237 href={shareMessage.whatsappLink}
238 className="d-none"
239 ref={whatsappLinkRef}
240 target="_blank"
241 rel="noopener noreferrer"
242 >
243 whatsapp link
244 </a>
245
246 <div className="text-center" style={{ marginTop: "18px" }}>
247 <button
248 className="btn btn-big"
249 type="button"
250 onClick={handleWhatsAppShareClick}
251 >
252 share via WhatsApp
253 </button>
254 </div>
255 </>
256 );
257};
258
259export default ActivityShare;