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/backend #9

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
NEXT_PUBLIC_APP_VERSION=0.0.1
NEXT_PUBLIC_APP_VERSION=0.0.1
NEXT_PUBLIC_BASE_URL=http://localhost:3001/
VERCEL_URL=
3 changes: 2 additions & 1 deletion .env-copy
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
NEXT_PUBLIC_APP_VERSION=0.0.1
NEXT_PUBLIC_APP_VERSION=0.0.1
NEXT_PUBLIC_BASE_URL=http://localhost:3000/
1 change: 1 addition & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions app/api/topics/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import fs from 'fs';
import path from 'path';
//import topics from '../../../data/speech-topics.json';

export async function GET(request: Request, {params}: any) {
try{
const jsonFilePath = path.join(process.cwd(), "data", "")

const textFilePath = path.join(process.cwd(), "data", "speech-topics-data.txt");
const textContent = fs.readFileSync(textFilePath, 'utf-8');
const textLines = textContent.split('\n');

const textTopics : {id:number, topic: string}[] = []
textLines.forEach((line) => {
const [_id, _topic] = line.split('. ', 2);
const id = parseInt(_id);
const topic: {id: number, topic: string} = {
id : id,
topic: `${_topic}`
}
textTopics.push(topic);
})

//const result= topics.concat(textTopics);

return new Response(JSON.stringify(textTopics), {
status: 200,
headers: {
'content-type': 'application/json'
}
})
} catch(error){
console.error('Error reading the file: ', error);
return new Response(JSON.stringify({error: "Error reading the file"}), {
status: 500,
headers: {
'content-type': 'application/json'
}
})
}
}
5 changes: 5 additions & 0 deletions app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use client'

export default function Error(){
return <div>Oh, No. Error occurred!</div>
}
26 changes: 1 addition & 25 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -1,27 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

/* :root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}

@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}

body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
} */
@tailwind utilities;
5 changes: 5 additions & 0 deletions app/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function Loading() {
return (
<div>Loading...</div>
)
}
157 changes: 21 additions & 136 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,144 +1,29 @@
'use client';
import { useState, useRef, useEffect } from 'react';
import { formatTime } from '@/utils/time-util-fns';
import { GetReadyTimer } from '@/components/GetReadyTimer';
import { SpeechTimer } from '@/components/SpeechTimer';
import { timeConfig } from '@/data/time-config';
import data from '../data/speech-topics.json';
import { TitleBar } from '@/components/TitleBar';
import { GoButton } from '@/components/GoButton';
import AppContainer from "@/components/AppContainer";

const countDownPeriodInSeconds: number = timeConfig.countDownPeriodInSeconds;

export default function Home() {
const [topic, setTopic] = useState('');
const [isTimerRunning, setIsTimerRunning] = useState(false);
const [elapsedTime, setElapsedTime] = useState(0);
const [savedTime, setSavedTime] = useState(0);
const timerRef = useRef<any>(null);
const appVersion = process.env.NEXT_PUBLIC_APP_VERSION;
const [countDownTimer, setCountDownTimer] = useState(
countDownPeriodInSeconds
);
const countDownIntervalId = useRef<any>(null);
const [isSpeechInProgress, setIsSpeechInProgress] = useState(false);

function startSpeech() {
startCountDown();
setTopic(generateRandomTopic());
setIsSpeechInProgress(true);
}

function endSpeech() {
setTopic('');
if (countDownIntervalId !== null) {
endCountDown();
}
if (isTimerRunning) {
stopTimer();
}
setIsSpeechInProgress(false);
async function getTopics(): Promise<{id: number, topic: string}[]> {
let baseUrl;
if(process.env.NEXT_PUBLIC_BASE_URL) {
baseUrl = process.env.NEXT_PUBLIC_BASE_URL
} else {
baseUrl = `https://${process.env.VERCEL_URL}/`
}
console.log(baseUrl);
const res = await fetch(`${baseUrl}api/topics`);

function startCountDown() {
if (countDownIntervalId.current !== null) return; // Don't start if it's already started
console.log('Content type:', res.headers.get('content-type'));

countDownIntervalId.current = setInterval(() => {
setCountDownTimer((prevTimer: number) => {
if (prevTimer <= 1) {
clearInterval(countDownIntervalId.current);
countDownIntervalId.current = null;
afterCountDown();
return 0;
}
return prevTimer - 1;
});
}, 1000);
console.log(res);
if(!res.ok){
console.log("res is not ok!")
throw new Error('Failed to fetch speech topics.');
}

function endCountDown() {
if (countDownIntervalId.current !== null) {
clearInterval(countDownIntervalId.current);
countDownIntervalId.current = null;
}
setCountDownTimer(countDownPeriodInSeconds);
}

function afterCountDown() {
startTimer();
console.log('Countdown finished');
}
console.log("res is ok!")

function startTimer() {
if (!isTimerRunning) {
setSavedTime(0);
setIsTimerRunning(true);
timerRef.current = setInterval(() => {
setElapsedTime((prevElapsedTime) => prevElapsedTime + 1);
}, 1000);
}
}

function stopTimer() {
if (isTimerRunning) {
setSavedTime(elapsedTime);
setIsTimerRunning(false);
clearInterval(timerRef.current);
setElapsedTime(0);
}
}

function generateRandomTopic(): string {
const randomIndex = Math.floor(Math.random() * data.length);
return data[randomIndex].topic;
}

useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.code === 'Space') {
event.preventDefault();
isSpeechInProgress ? endSpeech() : startSpeech();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [isSpeechInProgress]);

return (
<div className='min-h-screen p-5 flex flex-col items-center'>
<div className='md:mb-20 mb-5'>
{countDownIntervalId.current !== null || !isSpeechInProgress ? (
<GetReadyTimer time={countDownTimer} />
) : (
<SpeechTimer time={elapsedTime} />
)}
</div>
<div className='md:my-10 my-5'>
<GoButton
isSpeechInProgress={isSpeechInProgress}
endSpeech={endSpeech}
startSpeech={startSpeech}
/>
</div>
<div className="md:visible invisible">
<h5 className='text-sm font-semibold text-slate-400'>
Press Space Bar to start and stop.
</h5>
</div>
<TitleBar topic={topic} />
{savedTime !== 0 && (
<div className='md:my-10 my-2'>
<h3 className='text-xl'>
Your last time was{' '}
<span className='font-bold'>{formatTime(savedTime)}</span> minutes.
</h3>
</div>
)}
<div id='app-version-number' className='md:my-5 my-2'>
<span className='text-sm text-slate-400'>version {appVersion}</span>
</div>
</div>
);
return res.json();
}

export default async function Home(){
const topics = await getTopics();
return <AppContainer speechTopics={topics} />
}
Loading