Skip to content

Commit eb628fb

Browse files
committed
feat: implement streak sharing functionality with ShareStreakCard and ShareOptionsSheet components
1 parent 62ba4f6 commit eb628fb

3 files changed

Lines changed: 82 additions & 128 deletions

File tree

frontend/app/streak/page.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ const StreakCalendar: React.FC<StreakCalendarProps> = ({
162162
<div className="flex items-center justify-between mb-[20px]">
163163
<button
164164
onClick={handlePreviousMonth}
165-
className="p-2 rounded-lg hover:bg-[#FACC15]/10 transition-colors"
165+
className="p-2 rounded-lg hover:bg-[#FACC15]/10 transition-colors cursor-pointer"
166166
aria-label="Previous month"
167167
>
168168
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" className="text-[#FACC15]">
@@ -175,7 +175,7 @@ const StreakCalendar: React.FC<StreakCalendarProps> = ({
175175
</h2>
176176
<button
177177
onClick={handleNextMonth}
178-
className="p-2 rounded-lg hover:bg-[#FACC15]/10 transition-colors"
178+
className="p-2 rounded-lg hover:bg-[#FACC15]/10 transition-colors cursor-pointer"
179179
aria-label="Next month"
180180
>
181181
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" className="text-[#FACC15]">
@@ -333,7 +333,8 @@ const DEMO_STREAK_DATA: StreakData = (() => {
333333

334334
export default function StreakPage() {
335335
const router = useRouter();
336-
const [showShare, setShowShare] = useState(false);
336+
const [showShareCard, setShowShareCard] = useState(false);
337+
const [showShareSheet, setShowShareSheet] = useState(false);
337338

338339
const streakCount = 4;
339340
const points = 1100;
@@ -344,15 +345,15 @@ export default function StreakPage() {
344345
<StreakNavbar
345346
streakCount={streakCount}
346347
points={points}
347-
onShare={() => setShowShare(true)}
348+
onShare={() => setShowShareCard(true)}
348349
onClose={() => router.push("/dashboard")}
349350
/>
350351

351352
{/* Page Header */}
352353
<div className="w-full flex items-center justify-between px-[16px] md:px-8 pt-6 pb-2 max-w-[700px] mx-auto">
353354
<button
354355
onClick={() => router.push("/dashboard")}
355-
className="p-2 rounded-lg text-white/60 hover:text-white transition-colors"
356+
className="p-2 rounded-lg text-white/60 hover:text-white transition-colors cursor-pointer"
356357
aria-label="Close"
357358
>
358359
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
@@ -361,8 +362,8 @@ export default function StreakPage() {
361362
</button>
362363
<h1 className="font-nunito font-bold text-white text-lg tracking-wide">Streak</h1>
363364
<button
364-
onClick={() => setShowShare(true)}
365-
className="p-2 rounded-lg text-white/60 hover:text-white transition-colors"
365+
onClick={() => setShowShareCard(true)}
366+
className="p-2 rounded-lg text-white/60 hover:text-white transition-colors cursor-pointer"
366367
aria-label="Share"
367368
>
368369
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
@@ -401,8 +402,8 @@ export default function StreakPage() {
401402

402403
{/* Share Options Sheet */}
403404
<ShareOptionsSheet
404-
isOpen={showShare}
405-
onClose={() => setShowShare(false)}
405+
isOpen={showShareSheet}
406+
onClose={() => setShowShareSheet(false)}
406407
onShare={(platform) => {
407408
console.log(`Sharing streak to ${platform}`);
408409
// Handle sharing logic here
@@ -448,10 +449,14 @@ export default function StreakPage() {
448449
}}
449450
/>
450451
{/* Share Modal */}
451-
{showShare && (
452+
{showShareCard && (
452453
<ShareStreakCard
453454
streakCount={streakCount}
454-
onClose={() => setShowShare(false)}
455+
onClose={() => setShowShareCard(false)}
456+
onShare={() => {
457+
setShowShareCard(false);
458+
setShowShareSheet(true);
459+
}}
455460
/>
456461
)}
457462
</div>

frontend/components/ShareOptionsSheet.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ const ShareOptionsSheet: React.FC<ShareOptionsSheetProps> = ({
7777
};
7878
}, [isOpen, onClose]);
7979

80+
const handleTabKey = (event: React.KeyboardEvent) => {
81+
if (event.key !== 'Tab' || !sheetRef.current) return;
82+
83+
const focusable = sheetRef.current.querySelectorAll<HTMLElement>(
84+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
85+
);
86+
87+
if (focusable.length === 0) return;
88+
89+
const first = focusable[0];
90+
const last = focusable[focusable.length - 1];
91+
92+
if (event.shiftKey && document.activeElement === first) {
93+
event.preventDefault();
94+
last.focus();
95+
} else if (!event.shiftKey && document.activeElement === last) {
96+
event.preventDefault();
97+
first.focus();
98+
}
99+
};
100+
80101
// Prevent body scroll when sheet is open
81102
useEffect(() => {
82103
if (isOpen) {
@@ -101,7 +122,7 @@ const ShareOptionsSheet: React.FC<ShareOptionsSheetProps> = ({
101122
<div className="fixed inset-0 z-50 flex flex-col justify-end">
102123
{/* Backdrop */}
103124
<div
104-
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
125+
className="absolute inset-0 bg-black/60 backdrop-blur-sm cursor-pointer"
105126
onClick={onClose}
106127
aria-label="Close share options"
107128
/>
@@ -113,12 +134,13 @@ const ShareOptionsSheet: React.FC<ShareOptionsSheetProps> = ({
113134
role="dialog"
114135
aria-modal="true"
115136
aria-labelledby="share-sheet-title"
137+
onKeyDown={handleTabKey}
116138
>
117139
{/* Header */}
118140
<div className="flex items-center justify-between mb-6">
119141
<Button
120142
onClick={onClose}
121-
className="w-8 h-8 flex items-center justify-center text-white/60 hover:text-white transition-colors bg-transparent p-0"
143+
className="w-8 h-8 flex items-center justify-center text-white/60 hover:text-white transition-colors bg-transparent p-0 cursor-pointer"
122144
aria-label="Close share options"
123145
>
124146
<svg
@@ -153,7 +175,7 @@ const ShareOptionsSheet: React.FC<ShareOptionsSheetProps> = ({
153175
<button
154176
key={option.id}
155177
onClick={() => handleShare(option.id)}
156-
className="flex flex-col items-center gap-2 group focus:outline-none focus:ring-2 focus:ring-blue-500/50 rounded-lg p-2 transition-all duration-200"
178+
className="flex flex-col items-center gap-2 group focus:outline-none focus:ring-2 focus:ring-blue-500/50 rounded-lg p-2 transition-all duration-200 cursor-pointer"
157179
aria-label={`Share via ${option.label}`}
158180
>
159181
{/* Circular Icon Button */}

0 commit comments

Comments
 (0)