Skip to content

Commit

Permalink
refactor: extract scenario management logic into custom hook
Browse files Browse the repository at this point in the history
- Move scenario types to dedicated types/game.ts file
- Create useScenarioManager hook to handle scenario state and fetching
- Clean up game.tsx by removing redundant code and imports
- Improve type safety and code organization
- Fix typo in choiseScenarios -> choiceScenarios
  • Loading branch information
Ell1ott committed Dec 23, 2024
1 parent 28ca3e6 commit 32fccd9
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 96 deletions.
130 changes: 34 additions & 96 deletions app/game.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,56 @@
import { View, useWindowDimensions } from "react-native";
import { Text } from "~/components/ui/text";
import { Button } from "~/components/ui/button";
import { router } from "expo-router";
import { View } from "react-native";
import SwipeCard from "./components/swipe-card";
import { useEffect, useMemo, useState, useRef } from "react";
import { supabase } from "~/lib/supabase/client";
import { useSharedValue } from "react-native-reanimated";

// Card data type
export type ClientScenario = {
situation: string;
optionA: { text: string; id: number };
optionB: { text: string; id: number };
};
import { useState } from "react";
import { useScenarioManager } from "~/hooks/useScenarioManager";

const STARTING_SCENARIO_ID = 5;

export default function GameScreen() {
const [isAnimating, setIsAnimating] = useState(false);
// Add sample cards
const [cards, setCards] = useState<number[]>([1, 2, 3]);

const [MainCardContent, setMainCardContent] = useState(
"This is the first card"
);

const [isLoading, setIsLoading] = useState(false);
const [currentScenario, setCurrentScenario] = useState<ClientScenario | undefined>(
undefined
);
const choiseScenarios = useRef<{
optionA: ClientScenario | undefined;
optionB: ClientScenario | undefined;
}>({
optionA: undefined,
optionB: undefined,
});

useEffect(() => {
const initializeScenario = async () => {
try {
const { data } = await supabase.functions.invoke("generateScenario", {
body: { scenarioId: STARTING_SCENARIO_ID },
});

const generatedScenario: ClientScenario = data.data;
(["optionA", "optionB"] as const).map((key) => {
console.log(generatedScenario[key].id);
supabase.functions
.invoke("generateScenario", {
body: { scenarioId: generatedScenario[key].id },
})
.then((s) => {
console.log(key);
console.log(s.data.data);
choiseScenarios.current = {
...choiseScenarios.current,
[key]: s.data.data,
};
});
});
console.log(generatedScenario);
setCurrentScenario(generatedScenario);

// // Prefetch the next two scenarios

// );
} catch (error) {
console.error("Failed to load scenario:", error);
} finally {
setIsLoading(false);
}
};

initializeScenario();
}, []); // Empty dependency array means this runs once on mount
const {
currentScenario,
isLoading,
choiceScenarios,
nextCard,
setNextCard,
} = useScenarioManager(STARTING_SCENARIO_ID);

const handleDismiss = (direction: "optionA" | "optionB") => {
setIsAnimating(true);
console.log(`Card swiped ${direction}`);

setTimeout(() => {
// The animation should be stopped after 400ms
setIsAnimating(false);
// Remove card which was swiped
setCards((prevCards) => prevCards.slice(1));
setCurrentScenario(nextCard!);
}, 400);
};
const [nextCard, setNextCard] = useState<ClientScenario | undefined>({ situation: "This is the next card", optionA: { text: "Option A", id: 1 }, optionB: { text: "Option B", id: 2 } });

useEffect(() => {
console.log(nextCard);
}, [nextCard]);
const cardComponents =

// Memoize the card components

cards.map((card, index) => (
<SwipeCard
key={card}
card={{
title: `Card ${card}`,
description:
index === 0 ? currentScenario?.situation ?? "." : nextCard?.situation ?? ".",
}}
index={index - (isAnimating ? 1 : 0)}
totalCards={cards.length}
onDismiss={handleDismiss}
choiseScenarios={choiseScenarios}
setNextCard={setNextCard}

/>
));

const cardComponents = cards.map((card, index) => (
<SwipeCard
key={card}
card={{
title: `Card ${card}`,
description:
index === 0 ? currentScenario?.situation ?? "." : nextCard?.situation ?? ".",
}}
index={index - (isAnimating ? 1 : 0)}
totalCards={cards.length}
onDismiss={handleDismiss}
choiseScenarios={choiceScenarios}
setNextCard={setNextCard}
/>
));

if (isLoading) {
return (
<View className="flex-1 justify-center items-center">
<Text>Loading...</Text>
</View>
);
}

return (
<View className="flex-1 justify-center items-center p-6 bg-secondary/30">
Expand Down
60 changes: 60 additions & 0 deletions app/hooks/useScenarioManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState, useRef, useEffect } from 'react';
import { supabase } from "~/lib/supabase/client";
import type { ClientScenario } from '~/types/game';

export function useScenarioManager(startingScenarioId: number) {
const [currentScenario, setCurrentScenario] = useState<ClientScenario | undefined>();
const [isLoading, setIsLoading] = useState(false);
const [nextCard, setNextCard] = useState<ClientScenario | undefined>();

const choiceScenarios = useRef<{
optionA: ClientScenario | undefined;
optionB: ClientScenario | undefined;
}>({
optionA: undefined,
optionB: undefined,
});

const generateScenario = async (scenarioId: number) => {
const { data } = await supabase.functions.invoke("generateScenario", {
body: { scenarioId },
});
return data.data;
};

const prefetchNextScenarios = async (scenario: ClientScenario) => {
for (const key of ["optionA", "optionB"] as const) {
const nextScenario = await generateScenario(scenario[key].id);
choiceScenarios.current = {
...choiceScenarios.current,
[key]: nextScenario,
};
}
};

const initializeScenario = async () => {
try {
setIsLoading(true);
const generatedScenario = await generateScenario(startingScenarioId);
setCurrentScenario(generatedScenario);
await prefetchNextScenarios(generatedScenario);
} catch (error) {
console.error("Failed to load scenario:", error);
} finally {
setIsLoading(false);
}
};

useEffect(() => {
initializeScenario();
}, []);

return {
currentScenario,
setCurrentScenario,
isLoading,
choiceScenarios,
nextCard,
setNextCard,
};
}
5 changes: 5 additions & 0 deletions app/types/game.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type ClientScenario = {
situation: string;
optionA: { text: string; id: number };
optionB: { text: string; id: number };
};

0 comments on commit 32fccd9

Please sign in to comment.