From d373d95c9b0a635e4192403ec19e324cfa7868a3 Mon Sep 17 00:00:00 2001 From: Constantin Rusu Date: Thu, 8 May 2025 01:00:23 +0100 Subject: [PATCH] layout upgrades --- src/components/game/ExpertMemo.tsx | 4 +- src/components/game/IntroDialog.tsx | 26 +-- src/components/game/constants/gameStages.tsx | 204 ++++++++++++++++--- src/i18n/locales/en.json | 6 +- src/i18n/locales/ro.json | 6 +- src/pages/Index.tsx | 15 +- 6 files changed, 214 insertions(+), 47 deletions(-) diff --git a/src/components/game/ExpertMemo.tsx b/src/components/game/ExpertMemo.tsx index b97915a..e31b412 100644 --- a/src/components/game/ExpertMemo.tsx +++ b/src/components/game/ExpertMemo.tsx @@ -23,6 +23,7 @@ interface ExpertMemoProps { isAlert?: boolean; stage?: string; audioRef?: React.RefObject; + onStrategyClick?: (choiceNumber: number) => void; } export const ExpertMemo: React.FC = ({ @@ -31,7 +32,8 @@ export const ExpertMemo: React.FC = ({ children, isAlert = false, stage, - audioRef + audioRef, + onStrategyClick }) => { const { t } = useTranslation(); const [showGradient, setShowGradient] = useState(false); diff --git a/src/components/game/IntroDialog.tsx b/src/components/game/IntroDialog.tsx index 4506850..3b31813 100644 --- a/src/components/game/IntroDialog.tsx +++ b/src/components/game/IntroDialog.tsx @@ -77,7 +77,7 @@ export const IntroDialog = ({ onStartAudio }: IntroDialogProps) => {
@@ -130,23 +130,23 @@ export const IntroDialog = ({ onStartAudio }: IntroDialogProps) => {

{t('intro.howToPlay.description')}

-
-
- - {t('intro.howToPlay.features.monthlyBriefings')} +
+
+ + {t('intro.howToPlay.features.monthlyBriefings')}
-
- - {t('intro.howToPlay.features.trackProgress')} +
+ + {t('intro.howToPlay.features.trackProgress')}
-
- - {t('intro.howToPlay.features.strategicChoices')} +
+ + {t('intro.howToPlay.features.strategicChoices')}
- @@ -154,7 +154,7 @@ export const IntroDialog = ({ onStartAudio }: IntroDialogProps) => {

{t('intro.reminder')}

-
+ */}
diff --git a/src/components/game/constants/gameStages.tsx b/src/components/game/constants/gameStages.tsx index aa66382..8f94dd1 100644 --- a/src/components/game/constants/gameStages.tsx +++ b/src/components/game/constants/gameStages.tsx @@ -3,6 +3,7 @@ import { GameStage } from "../types"; import { ExpertMemo } from '../ExpertMemo'; import { useTranslation } from 'react-i18next'; import { ChoiceID } from './metrics'; +import { ChevronRightIcon } from "@heroicons/react/24/outline"; export const STAGE_CHOICES = [ [ChoiceID.DEPLOY_BOTS, ChoiceID.ESTABLISH_MEMES], // January @@ -17,7 +18,10 @@ export const STAGE_CHOICES = [ ] as const; // Create a custom hook to handle stages with translations -export const useGameStages = (audioRef: React.RefObject): GameStage[] => { +export const useGameStages = ( + audioRef: React.RefObject, + onStrategyClick?: (stage: number, choiceNumber: number) => void +): GameStage[] => { const { t } = useTranslation(); // Helper function to get translated month title @@ -42,14 +46,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.1.expertMemo.from')} subject={t('stages.1.expertMemo.subject')} stage="1" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(1, choice)} + >

{t('stages.1.expertMemo.content.greeting')}

{t('stages.1.expertMemo.content.intro')}

-

{t('stages.1.expertMemo.content.strategy1')}

+

onStrategyClick?.(1, 1)} + > + + Option 1: {t('stages.1.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.1.expertMemo.content.strategy2')}

+

onStrategyClick?.(1, 2)} + > + + Option 2: {t('stages.1.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.1.expertMemo.content.conclusion')}

@@ -121,14 +141,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.2.expertMemo.from')} subject={t('stages.2.expertMemo.subject')} stage="2" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(2, choice)} + >

{t('stages.2.expertMemo.content.greeting')}

{t('stages.2.expertMemo.content.intro')}

-

{t('stages.2.expertMemo.content.strategy1')}

+

onStrategyClick?.(2, 1)} + > + + Option 1: {t('stages.2.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.2.expertMemo.content.strategy2')}

+

onStrategyClick?.(2, 2)} + > + + Option 2: {t('stages.2.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.2.expertMemo.content.conclusion')}

@@ -198,14 +234,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.3.expertMemo.from')} subject={t('stages.3.expertMemo.subject')} stage="3" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(3, choice)} + >

{t('stages.3.expertMemo.content.greeting')}

{t('stages.3.expertMemo.content.intro')}

-

{t('stages.3.expertMemo.content.strategy1')}

+

onStrategyClick?.(3, 1)} + > + + Option 1: {t('stages.3.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.3.expertMemo.content.strategy2')}

+

onStrategyClick?.(3, 2)} + > + + Option 2: {t('stages.3.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.3.expertMemo.content.conclusion')}

@@ -277,14 +329,30 @@ export const useGameStages = (audioRef: React.RefObject): Game subject={t('stages.4.expertMemo.subject')} isAlert={true} stage="4" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(4, choice)} + >

{t('stages.4.expertMemo.content.greeting')}

{t('stages.4.expertMemo.content.intro')}

-

{t('stages.4.expertMemo.content.strategy1')}

+

onStrategyClick?.(4, 1)} + > + + Option 1: {t('stages.4.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.4.expertMemo.content.strategy2')}

+

onStrategyClick?.(4, 2)} + > + + Option 2: {t('stages.4.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.4.expertMemo.content.conclusion')}

@@ -355,14 +423,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.5.expertMemo.from')} subject={t('stages.5.expertMemo.subject')} stage="5" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(5, choice)} + >

{t('stages.5.expertMemo.content.greeting')}

{t('stages.5.expertMemo.content.intro')}

-

{t('stages.5.expertMemo.content.strategy1')}

+

onStrategyClick?.(5, 1)} + > + + Option 1: {t('stages.5.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.5.expertMemo.content.strategy2')}

+

onStrategyClick?.(5, 2)} + > + + Option 2: {t('stages.5.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.5.expertMemo.content.conclusion')}

@@ -433,14 +517,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.6.expertMemo.from')} subject={t('stages.6.expertMemo.subject')} stage="6" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(6, choice)} + >

{t('stages.6.expertMemo.content.greeting')}

{t('stages.6.expertMemo.content.intro')}

-

{t('stages.6.expertMemo.content.strategy1')}

+

onStrategyClick?.(6, 1)} + > + + Option 1: {t('stages.6.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.6.expertMemo.content.strategy2')}

+

onStrategyClick?.(6, 2)} + > + + Option 2: {t('stages.6.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.6.expertMemo.content.conclusion')}

@@ -511,14 +611,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.7.expertMemo.from')} subject={t('stages.7.expertMemo.subject')} stage="7" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(7, choice)} + >

{t('stages.7.expertMemo.content.greeting')}

{t('stages.7.expertMemo.content.intro')}

-

{t('stages.7.expertMemo.content.strategy1')}

+

onStrategyClick?.(7, 1)} + > + + Option 1: {t('stages.7.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.7.expertMemo.content.strategy2')}

+

onStrategyClick?.(7, 2)} + > + + Option 2: {t('stages.7.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.7.expertMemo.content.conclusion')}

@@ -589,14 +705,30 @@ export const useGameStages = (audioRef: React.RefObject): Game from={t('stages.8.expertMemo.from')} subject={t('stages.8.expertMemo.subject')} stage="8" - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(8, choice)} + >

{t('stages.8.expertMemo.content.greeting')}

{t('stages.8.expertMemo.content.intro')}

-

{t('stages.8.expertMemo.content.strategy1')}

+

onStrategyClick?.(8, 1)} + > + + Option 1: {t('stages.8.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.8.expertMemo.content.strategy2')}

+

onStrategyClick?.(8, 2)} + > + + Option 2: {t('stages.8.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.8.expertMemo.content.conclusion')}

@@ -668,14 +800,30 @@ export const useGameStages = (audioRef: React.RefObject): Game subject={t('stages.9.expertMemo.subject')} stage="9" isAlert={true} - audioRef={audioRef}> + audioRef={audioRef} + onStrategyClick={(choice) => onStrategyClick?.(9, choice)} + >

{t('stages.9.expertMemo.content.greeting')}

{t('stages.9.expertMemo.content.intro')}

-

{t('stages.9.expertMemo.content.strategy1')}

+

onStrategyClick?.(9, 1)} + > + + Option 1: {t('stages.9.choices.1.text')} + ({t('common.clickForDetails')}) +

-

{t('stages.9.expertMemo.content.strategy2')}

+

onStrategyClick?.(9, 2)} + > + + Option 2: {t('stages.9.choices.2.text')} + ({t('common.clickForDetails')}) +

{t('stages.9.expertMemo.content.conclusion')}

diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 3be9285..3831612 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -85,7 +85,7 @@ "explanation": "While this may seem absurd, the techniques you'll encounter mirror real-world disinformation tactics. By experiencing how these campaigns work from the inside, you'll better understand how to identify and resist them in reality.", "howToPlay": { "title": "How to Play", - "description": "You will progress through a year-long simulation where you'll make strategic choices on how to invest your resources. Each month, you'll analyze expert briefings and choose between different strategies. Your decisions will affect your campaign's reach, supporter loyalty, and viral spread. Track your progress in the mission dossier and adapt your approach based on results.", + "description": "Progress through a year-long simulation, making strategic choices each month. Review expert briefings, track your progress, and adapt your approach based on results.", "features": { "monthlyBriefings": "Monthly Briefings", "trackProgress": "Track Progress", @@ -802,5 +802,9 @@ "showLess": "Show Less", "learnMore": "Real-World Examples", "readArticle": "Read Article" + }, + "common": { + "loading": "Loading...", + "clickForDetails": "click for details" } } \ No newline at end of file diff --git a/src/i18n/locales/ro.json b/src/i18n/locales/ro.json index aa92277..72030d9 100644 --- a/src/i18n/locales/ro.json +++ b/src/i18n/locales/ro.json @@ -85,7 +85,7 @@ "explanation": "Deși poate părea absurd, tehnicile pe care le vei întâlni reflectă tacticile de dezinformare din lumea reală. Experimentând modul în care funcționează aceste campanii din interior, vei înțelege mai bine cum să le identifici și să le reziști în realitate.", "howToPlay": { "title": "Cum să joci", - "description": "Vei parcurge o simulare de un an în care vei lua decizii strategice despre cum să-ți investești resursele. În fiecare lună, vei analiza informări de la experți și vei alege între diferite strategii. Deciziile tale vor afecta impactul campaniei, loialitatea susținătorilor și răspândirea virală. Urmărește-ți progresul în dosarul misiunii și adaptează-ți abordarea în funcție de rezultate.", + "description": "Parcurge o simulare de un an, luând decizii strategice în fiecare lună. Analizează briefing-urile experților, urmărește-ți progresul și adaptează-ți abordarea în funcție de rezultate.", "features": { "monthlyBriefings": "Briefing-uri Lunare", "trackProgress": "Urmărește Progresul", @@ -802,5 +802,9 @@ "showLess": "Arată mai puțin", "learnMore": "Exemple din lumea reală", "readArticle": "Citește articolul" + }, + "common": { + "loading": "Se încarcă...", + "clickForDetails": "click pentru detalii" } } diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index cefeb5b..1bda7e8 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -47,7 +47,16 @@ const Index = () => { const { t, i18n } = useTranslation(); const audioRef = useRef(null); const [previousChoices, setPreviousChoices] = useState([]); - const stages = useGameStages(audioRef); + const stages = useGameStages(audioRef, (stage, choice) => { + // Find the stage and choice + const currentStageData = stages[stage - 1]; + if (currentStageData) { + const selectedChoice = currentStageData.choices[choice - 1]; + if (selectedChoice) { + handleStrategyClick(selectedChoice); + } + } + }); const operationNameKey = OPERATION_NAMES[Math.floor(Math.random() * OPERATION_NAMES.length)]; const operationName = t(`operations.${operationNameKey}`); const [agentNumber] = useState(Math.floor(Math.random() * 999).toString().padStart(3, '0')); @@ -603,7 +612,7 @@ const Index = () => {
- + {/*
{(() => { console.log('Index - Rendering stage:', currentStage); @@ -619,7 +628,7 @@ const Index = () => { )); })()}
-
+
*/}