Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/33 breaking out game recap components #34

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_API_URL=http://127.0.0.1:5000/
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_API_URL=https://imaginate-api-818978516440.us-central1.run.app/
46 changes: 21 additions & 25 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,53 @@
import { useState, useRef, ReactElement, useEffect } from 'react';
import './App.css';
import Navbar from './navigation/Navbar';
import NavBar from './components/NavBar/NavBar.tsx';
import { ConfigProvider, theme, Flex } from 'antd';

import posthog from 'posthog-js';
import Cookies from 'universal-cookie';
import { PhotoQueue } from './photoQueue/photoQueue.tsx';
import { getImages } from './services/imageBackend.ts';
import { Image } from './photoQueue/interfaces/ImageInterface.ts';
import PhotoQueue from './components/PhotoQueue/PhotoQueue.tsx';
import { getImages } from './services/Image.service.ts';
import { Choice, Image } from './types/Image.types.ts';
import { calculateDay } from './services/Day.service.ts';
import { generateScoreHTML } from './services/Score.service.tsx';

const cookies = new Cookies();
const day = calculateDay();

function App() {
const { darkAlgorithm } = theme;
const [showApp, setShowApp] = useState(true);
const savedScoreString = useRef<ReactElement>();
const scoreText = useRef<ReactElement>();
const [images, setImages] = useState<Image[]>([]);
const [imageTheme, setImageTheme] = useState('');

useEffect(() => {
getImages().then((response: Image[]) => {
getImages().then((response: Image[] | undefined) => {
if (response) {
setImages(response);
setImageTheme(response[0].theme);
}
});
}, []);

const splitNewlinesToParagraphTags = (input: string) => {
return input.split('\n').map((text) => <p key={text}>{text}</p>);
};

useEffect(() => {
const dayLastPlayed = new Date(cookies.get('day_last_played'));
const completeScoreText: string = cookies.get('last_complete_score_text');
const today = new Date();
today.setHours(0, 0, 0, 0);
if (
dayLastPlayed.toDateString() === today.toDateString() &&
completeScoreText
) {
setShowApp(false);
savedScoreString.current = (
<div>{splitNewlinesToParagraphTags(completeScoreText)}</div>
);
const storedDayLastPlayed = Number(localStorage.getItem('day_last_played'));
const storedLastChoiceKeeper = localStorage.getItem('last_choice_keeper');
if (storedDayLastPlayed && storedLastChoiceKeeper) {
const today = new Date().setHours(0, 0, 0, 0);
const dayLastPlayed = new Date(storedDayLastPlayed).setHours(0, 0, 0, 0);
const lastChoiceKeeper: Choice[] = JSON.parse(storedLastChoiceKeeper);
if (dayLastPlayed === today) {
setShowApp(false);
scoreText.current = generateScoreHTML(lastChoiceKeeper, day);
}
}
}, []);

const dailyGameReminder = (
<div className='text-center'>
<p className='font-semibold mb-2'>You already played today!</p>
<p className='font-semibold mb-2'>See you again tomorrow :)</p>
{savedScoreString.current}
{scoreText.current}
</div>
);

Expand All @@ -69,7 +65,7 @@ function App() {
className='h-full w-full '
vertical
>
<Navbar theme={imageTheme} />
<NavBar theme={imageTheme} />
<Flex
align='center'
justify='space-evenly'
Expand Down
43 changes: 43 additions & 0 deletions src/components/GameRecap/GameRecap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Flex } from 'antd';
import { Choice } from '../../types/Image.types';
import PhotoCarousel from '../PhotoCarousel/PhotoCarousel';
import ShareButton from '../ShareButton/ShareButton';
import { useMemo } from 'react';
import { calculateDay as calculateDay } from '../../services/Day.service';
import { generateScoreText } from '../../services/Score.service';

type GameRecapProps = {
choices: Choice[];
};

const day = calculateDay();

const GameRecap = ({ choices }: GameRecapProps) => {
const score = useMemo(() => {
return choices.filter((choice) => {
choice.isCorrect;
}).length;
}, [choices]);

const scoreText = useMemo(() => generateScoreText(choices, day), [choices]);

return (
<div className='w-full'>
<Flex
justify='center'
align='center'
gap={'1rem'}
className='text-center'
vertical
>
<p className='text-2xl'>
You got {score} out of {choices.length} correct!
</p>
<PhotoCarousel choices={choices} />
<ShareButton scoreText={scoreText} />
</Flex>
</div>
);
};

export default GameRecap;
File renamed without changes.
13 changes: 8 additions & 5 deletions src/navigation/Navbar.tsx → src/components/NavBar/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Divider, Flex, Tooltip } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons';
import logo from '../assets/imaginate-logo.png';
import './Navbar.css';
import { NavBarProps } from '../interfaces/NavBarProps';
import logo from '../../assets/imaginate-logo.png';
import './NavBar.css';

const THEME_EXPLAINER_TEXT = 'The theme changes every day!';

const Navbar = ({ theme }: NavBarProps) => {
type NavBarProps = {
theme: string | undefined;
};

const NavBar = ({ theme }: NavBarProps) => {
return (
<div className='w-full'>
<Flex align='flex-end' justify='space-between' wrap>
Expand All @@ -30,4 +33,4 @@ const Navbar = ({ theme }: NavBarProps) => {
);
};

export default Navbar;
export default NavBar;
57 changes: 57 additions & 0 deletions src/components/PhotoCarousel/PhotoCarousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Carousel } from 'antd';
import { Choice } from '../../types/Image.types';
import { CloseOutlined, CheckOutlined } from '@ant-design/icons';
import { useMemo } from 'react';

type PhotoCarouselProps = {
choices: Choice[];
};

const PhotoCarousel = ({ choices }: PhotoCarouselProps) => {
const answers = useMemo(() => {
return buildAnswers(choices);
}, [choices]);

return (
<Carousel
arrows
dotPosition='left'
infinite={false}
className='flex gap-4'
style={{ width: '100%' }}
>
{answers}
</Carousel>
);
};

const buildAnswers = (choices: Choice[]) => {
return choices.map(({ isCorrect: correct, image }) => {
const generatedText = image.real ? 'real' : 'AI';
const feedbackIcon = correct ? (
<CheckOutlined className='text-6xl text-green-600 absolute bottom-6 right-6 z-10' />
) : (
<CloseOutlined className='text-6xl text-red-600 absolute bottom-6 right-6 z-10' />
);
return (
<div className='p-8' key={image.url}>
<div className='flex justify-center '>
<div className='relative p-4'>
<img
className={
'rounded-lg border-solid border-2 z-0 ' +
(correct ? 'border-green-500' : 'border-red-500')
}
style={{ maxWidth: '100%' }}
src={`data:image/png;base64,${image.data}`}
/>
{feedbackIcon}
</div>
</div>
<p className='text-2xl'>This photo is {generatedText}</p>
</div>
);
});
};

export default PhotoCarousel;
Loading