Skip to content

Commit 2e4d1de

Browse files
committed
Add sharing functionality for completed puzzles and handle puzzle query parameter
1 parent 7aefdde commit 2e4d1de

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

frontend/public/x-logo.png

654 Bytes
Loading

frontend/src/components/puzzles/PuzzleSubmit.tsx

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ export function PuzzleSubmit({
150150

151151
const buttonText = isPuzzleCompleted ? "Already Completed" : "Submit Solution";
152152

153+
const handleShareClick = () => {
154+
if (!puzzle) return;
155+
156+
const puzzleUrl = `${window.location.origin}/?puzzle=${puzzle.id}`;
157+
const tweetText = `I just solved "${puzzle.title}" on Linera Game of Life! \n\nTry it yourself: ${puzzleUrl}`;
158+
const twitterIntentUrl = `https://x.com/intent/tweet?text=${encodeURIComponent(tweetText)}`;
159+
160+
window.open(twitterIntentUrl, "_blank", "noopener,noreferrer");
161+
};
162+
153163
return (
154164
<Card className="bg-white shadow-lg">
155165
<CardBody className="p-6">
@@ -158,15 +168,25 @@ export function PuzzleSubmit({
158168

159169
{validationResult && <ValidationMessage result={validationResult} />}
160170

161-
<Button
162-
onPress={onSubmit}
163-
isLoading={isSubmitting}
164-
isDisabled={isPuzzleCompleted}
165-
className={`w-full font-medium ${buttonClassName}`}
166-
size="lg"
167-
>
168-
{buttonText}
169-
</Button>
171+
{isPuzzleCompleted ? (
172+
<Button
173+
onPress={handleShareClick}
174+
className="w-full font-medium bg-linera-primary hover:bg-linera-primary-dark text-white"
175+
size="lg"
176+
endContent={<img src="/x-logo.png" alt="X" className="w-5 h-5" />}
177+
>
178+
Share on
179+
</Button>
180+
) : (
181+
<Button
182+
onPress={onSubmit}
183+
isLoading={isSubmitting}
184+
className={`w-full font-medium ${buttonClassName}`}
185+
size="lg"
186+
>
187+
{buttonText}
188+
</Button>
189+
)}
170190
</div>
171191
</CardBody>
172192
</Card>

frontend/src/lib/game-of-life/hooks/usePuzzleGame.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useState, useCallback } from "react";
1+
import { useState, useCallback, useEffect } from "react";
2+
import { useSearchParams } from "react-router-dom";
23
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
34
import { LineraService } from "@/lib/linera/services/LineraService";
45
import { LineraBoard } from "@/lib/types/puzzle.types";
@@ -12,6 +13,7 @@ const QUERY_KEYS = {
1213
};
1314

1415
export function usePuzzleGame() {
16+
const [searchParams] = useSearchParams();
1517
const [currentPuzzleId, setCurrentPuzzleId] = useState<string | null>(null);
1618
const [stepCount, setStepCount] = useState(0);
1719
const [validationResult, setValidationResult] = useState<{
@@ -222,6 +224,20 @@ export function usePuzzleGame() {
222224
game.clear();
223225
}, [game]);
224226

227+
// Handle puzzle query parameter on mount
228+
useEffect(() => {
229+
if (!isInitialized) return;
230+
231+
const puzzleIdFromUrl = searchParams.get('puzzle');
232+
if (puzzleIdFromUrl) {
233+
// Check if the puzzle ID exists in KNOWN_PUZZLES
234+
const puzzleExists = KNOWN_PUZZLES.some(p => p.id === puzzleIdFromUrl);
235+
if (puzzleExists && !currentPuzzleId) {
236+
loadPuzzle(puzzleIdFromUrl);
237+
}
238+
}
239+
}, [isInitialized, searchParams, currentPuzzleId, loadPuzzle]);
240+
225241
// Navigation functions
226242
const loadNextPuzzle = useCallback(() => {
227243
if (!currentPuzzleId) return false;

0 commit comments

Comments
 (0)