Skip to content

Commit

Permalink
Merge pull request #106 from the-ai-team/feature/105-race-page-develo…
Browse files Browse the repository at this point in the history
…pment

[Related #105] Race page development
  • Loading branch information
supunTE authored Mar 18, 2024
2 parents 5f6002c + 1040eb2 commit d810eea
Show file tree
Hide file tree
Showing 56 changed files with 1,166 additions and 316 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function AvatarArray({
return (
<div
className={cs(
'absolute pt-1 -left-[7.5rem]',
'absolute pt-1 -left-[6.5rem]',
'flex items-center justify-end',
)}
style={style}>
Expand All @@ -35,7 +35,7 @@ export function AvatarArray({
key={reversedIndex}
id={`avatar-${reversedIndex}`}
className={cs(
'w-8 h-8 rounded-full border-2 border-neutral-20',
'w-7 h-7 rounded-full border-2 border-neutral-20',
'flex items-center justify-center',
{
'-ml-2': index !== 0,
Expand Down
61 changes: 37 additions & 24 deletions apps/client/src/components/molecules/timer/Timer.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Text } from '../../atoms';

export interface TimerProps {
time: number; // in seconds
onTimeEnd: () => void;
onTimeEnd?: () => void;
}

/**
Expand All @@ -27,6 +27,25 @@ export function Timer({
const timerEnded = useRef(false);

useEffect(() => {
startTimestamp.current = Date.now();
previousTimestamp.current = Date.now();
setSeconds(time);
setMilliseconds(0);
timerEnded.current = false;
}, [time]);

useEffect(() => {
const circle = circleIndicator.current;
let circumference: number;

if (circle) {
const radius = circle.r.baseVal.value;
// C=2πr
circumference = 2 * Math.PI * radius;
// Fill circle dash
circle.setAttribute('stroke-dasharray', `${circumference}, 20000`);
}

const updateTimer = (): void => {
if (timerEnded.current) {
return;
Expand All @@ -42,39 +61,33 @@ export function Timer({
previousTimestamp.current = now;
const delta = now - startTimestamp.current;

const remainingSeconds = Math.max(0, time - Math.floor(delta / 1000));
const remainingMilliseconds = Math.max(
0,
99 - Math.floor((delta % 1000) / 10),
const remainingTime = time * 1000 - delta;
const remainingSeconds = Math.max(0, Math.floor(remainingTime / 1000));
const remainingMilliseconds = Math.floor(
(remainingTime - remainingSeconds * 1000) / 10,
);
setSeconds(remainingSeconds);
setMilliseconds(remainingMilliseconds);

const circle = circleIndicator.current;

if (circle) {
const radius = circle.r.baseVal.value;
// C=2πr
const circumference = 2 * Math.PI * radius;

let dashOffset = (delta / 1000 / time) * circumference;
dashOffset = Math.min(circumference, Math.max(0, dashOffset));
// Dash offset = Fraction of time elapsed * circumference
let dashOffset = (remainingTime / (time * 1000)) * circumference;
// Clamp dash offset to the circumference
dashOffset = Math.min(circumference, dashOffset);

circle.setAttribute('stroke-dasharray', `${circumference}`);
circle.setAttribute(
'stroke-dashoffset',
`${circumference - dashOffset}`,
);
}

// When time is up setting seconds and milliseconds to 0
if (time <= delta / 1000) {
clearInterval(interval);
timerEnded.current = true;
console.log(Date.now() - startTimestamp.current);
setSeconds(0);
setMilliseconds(0);
onTimeEnd();
}
// When time is up setting seconds and milliseconds to 0
if (remainingTime <= 0) {
clearInterval(interval);
timerEnded.current = true;
setSeconds(0);
setMilliseconds(0);
onTimeEnd();
}

requestAnimationFrame(updateTimer);
Expand All @@ -87,6 +100,7 @@ export function Timer({
return (
<div
className={cs(
'm-auto',
'rounded-full bg-neutral-20 inline-block',
'w-72 aspect-square',
'flex justify-center items-center',
Expand Down Expand Up @@ -126,7 +140,6 @@ export function Timer({
r='40%'
fill='none'
strokeWidth='15'
strokeDasharray='0,20000'
strokeLinecap='round'
transform='rotate(-90,150,150)'
className='stroke-neutral-90'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ export function Panel({ title, children }: PanelProps): ReactElement {
return (
<div
className={cs(
{ 'h-40 pt-6': isCollapse },
{ 'h-2/3 pt-20 pb-24': !isCollapse },
{ 'h-32 pt-4': isCollapse },
{ 'h-2/3 pt-12 pb-20': !isCollapse },
'flex flex-col',
'absolute top-5 right-5 z-50',
'px-10',
'px-12',
'w-1/3 max-w-xl max-h-[1200px] min-w-[400px] rounded-md bg-neutral-20',
'border border-neutral-40',
'hover:ring-4 hover:ring-neutral-40',
Expand Down
4 changes: 4 additions & 0 deletions apps/client/src/constants/connection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { REQUEST_WAITING_TIME } from '@razor/constants';

export const REQUEST_WAITING_TIME_FOR_CLIENT =
import.meta.env.VITE_REQUEST_WAITING_TIME || REQUEST_WAITING_TIME;
1 change: 1 addition & 0 deletions apps/client/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * as Connection from './connection';
export * as Race from './race';
export * as TextStyles from './text-styles';
export * as Time from './time';
2 changes: 2 additions & 0 deletions apps/client/src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './create-tournament.controller';
export * from './join-tournament.controller';
export * from './player-join.controller';
export * from './start-race.controller';
export * from './update-type-logs.controller';
48 changes: 25 additions & 23 deletions apps/client/src/controllers/player-join.controller.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import { playerStateToAppPlayerState, SocketProtocols } from '@razor/models';
import { AddPlayerPayload, store } from '@razor/store';

import { AllServerPubSubEventsToTypeMap } from '../models';
import { AllClientPubSubEventsToTypeMap } from '../models';
import { pubsub } from '../utils/pubsub';

pubsub.subscribe(
SocketProtocols.PlayerJoin,
({
data,
tournamentId,
}: AllServerPubSubEventsToTypeMap[SocketProtocols.PlayerJoin]) => {
const { id: playerId, state, ...playerData } = data.player;
type PlayerJoinControllerArgs =
AllClientPubSubEventsToTypeMap[SocketProtocols.PlayerJoin];

// converted PlayerState to AppPlayerState,
// because we're using two models for store and socket
const appPlayerState = playerStateToAppPlayerState(state);
function playerJoinController({
data,
tournamentId,
}: PlayerJoinControllerArgs): void {
const { id: playerId, state, ...playerData } = data.player;

const dataToDispatch: AddPlayerPayload = {
playerId,
player: {
...playerData,
state: appPlayerState,
// This is equal because received player and joined player on same tournament
tournamentId,
},
};
// converted PlayerState to AppPlayerState,
// because we're using two models for store and socket
const appPlayerState = playerStateToAppPlayerState(state);

store.dispatch.game.addPlayer({ ...dataToDispatch });
},
);
const dataToDispatch: AddPlayerPayload = {
playerId,
player: {
...playerData,
state: appPlayerState,
// This is equal because received player and joined player on same tournament
tournamentId,
},
};

store.dispatch.game.addPlayer({ ...dataToDispatch });
}

pubsub.subscribe(SocketProtocols.PlayerJoin, playerJoinController);
23 changes: 23 additions & 0 deletions apps/client/src/controllers/start-race.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { SocketProtocols } from '@razor/models';
import { store } from '@razor/store';

import { AllClientPubSubEventsToTypeMap } from '../models';
import { pubsub } from '../utils/pubsub';

type StartRaceControllerArgs =
AllClientPubSubEventsToTypeMap[SocketProtocols.StartRaceAccept];

function StartRaceController({
data,
tournamentId,
}: StartRaceControllerArgs): void {
const { raceStartedBy, raceText, ..._ } = data;

store.dispatch.game.startCountdown({
tournamentId,
playerId: raceStartedBy,
raceText,
});
}

pubsub.subscribe(SocketProtocols.StartRaceAccept, StartRaceController);
32 changes: 32 additions & 0 deletions apps/client/src/controllers/update-type-logs.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PlayerId, SocketProtocols } from '@razor/models';
import { store } from '@razor/store';

import { AllClientPubSubEventsToTypeMap } from '../models';
import { pubsub } from '../utils/pubsub';

type UpdateTypeLogsControllerArgs =
AllClientPubSubEventsToTypeMap[SocketProtocols.UpdateTypeLogs];

function updateTypeLogsController({
data,
savedPlayerId,
}: UpdateTypeLogsControllerArgs): void {
const { raceId, playerLogs: playersLogs } = data;
const race = store.getState().game.racesModel[raceId];
const racePlayerIds = Object.keys(race.players) as PlayerId[];

for (const playerId of racePlayerIds) {
const logs = playersLogs[playerId];
if (!logs || playerId === savedPlayerId) {
continue;
}

store.dispatch.game.sendTypeLog({
playerLog: logs,
playerId,
raceId,
});
}
}

pubsub.subscribe(SocketProtocols.UpdateTypeLogs, updateTypeLogsController);
8 changes: 7 additions & 1 deletion apps/client/src/i18n/en/race.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"page": "Race"
"page": "Race",
"toasts": {
"race_start": {
"title": "Ready, set, go!",
"message": "{{player_name}} started the race. Good luck!"
}
}
}
2 changes: 1 addition & 1 deletion apps/client/src/models/pubsub/pubsub-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ type ModifiedOtherProtocolToTypeMap = {
>;
};

export type AllServerPubSubEventsToTypeMap = ClientUniqueEventsToTypeMap &
export type AllClientPubSubEventsToTypeMap = ClientUniqueEventsToTypeMap &
InitialProtocolToTypeMap &
ModifiedOtherProtocolToTypeMap;
4 changes: 2 additions & 2 deletions apps/client/src/pages/home/Home.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import {
Text,
} from '../../components';
import { TextSize, TextType } from '../../models';
import { endSocket } from '../../services';
import {
endSocket,
requestToCreateRoom,
requestToJoinRoom,
} from '../../services';
} from '../../services/handlers';

export function Home(): ReactElement {
const { t } = useTranslation('home');
Expand Down
Loading

0 comments on commit d810eea

Please sign in to comment.