You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
9.6 KiB
TypeScript
309 lines
9.6 KiB
TypeScript
import { sendJSON } from '@/client/utils'
|
|
import type { Room, RoomData } from '@/db/model'
|
|
import { type Action, type ActionAnswer, type ActionJolly } from '@/ggwp'
|
|
import { formatDate, parse } from 'date-fns'
|
|
import { useState } from 'preact/hooks'
|
|
import { Clock } from './time'
|
|
|
|
type Outcome = 'correct' | 'partial' | 'wrong'
|
|
|
|
export const SubmitActionAnswer = ({
|
|
room,
|
|
sendAction,
|
|
onTeamQuestionIndex,
|
|
}: {
|
|
room: RoomData
|
|
sendAction: (action: Action) => void
|
|
onTeamQuestionIndex?: Receiver<{ team: string; question: string }>
|
|
}) => {
|
|
const [answer, setAnswer] = useState<Omit<ActionAnswer, 'timestamp'>>({
|
|
question: '',
|
|
team: '',
|
|
outcome: 'correct',
|
|
})
|
|
|
|
onTeamQuestionIndex?.('SubmitActionAnswer', ({ team, question }) => {
|
|
console.log('onTeamQuestionIndex', team, question)
|
|
setAnswer(answer => ({ ...answer, team, question }))
|
|
})
|
|
|
|
return (
|
|
<div class="card tint-green stack-v center">
|
|
<h3>
|
|
Invia Risposta Immediata (<Clock />)
|
|
</h3>
|
|
|
|
<select
|
|
class="fill-w"
|
|
placeholder="Domanda..."
|
|
value={answer.question}
|
|
onInput={e => setAnswer({ ...answer, question: e.currentTarget.value })}
|
|
>
|
|
<option value="" disabled>
|
|
Seleziona domanda...
|
|
</option>
|
|
{room.questions.map((question, i) => (
|
|
<option value={question.id} key={i}>
|
|
{question.id}
|
|
</option>
|
|
))}
|
|
</select>
|
|
|
|
<select
|
|
class="fill-w"
|
|
placeholder="Squadra..."
|
|
value={answer.team}
|
|
onInput={e => setAnswer({ ...answer, team: e.currentTarget.value })}
|
|
>
|
|
<option value="" disabled>
|
|
Seleziona squadra...
|
|
</option>
|
|
{room.teams.map((team, i) => (
|
|
<option value={team} key={i}>
|
|
{team}
|
|
</option>
|
|
))}
|
|
</select>
|
|
|
|
<select
|
|
class="fill-w"
|
|
value={answer.outcome}
|
|
onInput={e => setAnswer({ ...answer, outcome: e.currentTarget.value as Outcome })}
|
|
>
|
|
<option value="correct">Corretta</option>
|
|
<option value="partial">Parziale</option>
|
|
<option value="wrong">Sbagliata</option>
|
|
</select>
|
|
|
|
<div class="stack-h">
|
|
<button
|
|
onClick={() =>
|
|
sendAction({
|
|
...answer,
|
|
type: 'answer',
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
}
|
|
>
|
|
Invia risposta
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const SubmitActionAnswerAtTime = ({
|
|
room,
|
|
sendAction,
|
|
onTeamQuestionIndex,
|
|
}: {
|
|
room: RoomData
|
|
sendAction: (action: Action) => void
|
|
onTeamQuestionIndex?: Receiver<{ team: string; question: string }>
|
|
}) => {
|
|
type ActionTimeAnswer = Omit<ActionAnswer, 'timestamp'> & { timestampRaw: string }
|
|
|
|
const [answer, setAnswer] = useState<ActionTimeAnswer>({
|
|
timestampRaw: '',
|
|
question: '',
|
|
team: '',
|
|
outcome: 'correct',
|
|
})
|
|
|
|
onTeamQuestionIndex?.('SubmitActionAnswerAtTime', ({ team, question }) => {
|
|
console.log('onTeamQuestionIndex', team, question)
|
|
setAnswer(answer => ({ ...answer, team, question }))
|
|
})
|
|
|
|
return (
|
|
<div class="card tint-green stack-v center">
|
|
<h3>Invia Risposta al Tempo</h3>
|
|
|
|
<div class="stack-h fill-w">
|
|
<input
|
|
type="text"
|
|
class="fill"
|
|
placeholder={'Tempo in formato HH:mm:ss...'}
|
|
value={answer.timestampRaw}
|
|
onInput={e => setAnswer({ ...answer, timestampRaw: e.currentTarget.value })}
|
|
/>
|
|
|
|
<button onClick={() => setAnswer({ ...answer, timestampRaw: formatDate(new Date(), 'HH:mm:ss') })}>
|
|
Aggiorna Tempo
|
|
</button>
|
|
</div>
|
|
|
|
<select
|
|
class="fill-w"
|
|
placeholder="Domanda..."
|
|
value={answer.question}
|
|
onInput={e => setAnswer({ ...answer, question: e.currentTarget.value })}
|
|
>
|
|
<option value="" disabled>
|
|
Seleziona domanda...
|
|
</option>
|
|
{room.questions.map((question, i) => (
|
|
<option value={question.id} key={i}>
|
|
{question.id}
|
|
</option>
|
|
))}
|
|
</select>
|
|
|
|
<select
|
|
class="fill-w"
|
|
placeholder="Squadra..."
|
|
value={answer.team}
|
|
onInput={e => setAnswer({ ...answer, team: e.currentTarget.value })}
|
|
>
|
|
<option value="" disabled>
|
|
Seleziona squadra...
|
|
</option>
|
|
{room.teams.map((team, i) => (
|
|
<option value={team} key={i}>
|
|
{team}
|
|
</option>
|
|
))}
|
|
</select>
|
|
|
|
<select
|
|
class="fill-w"
|
|
value={answer.outcome}
|
|
onInput={e => setAnswer({ ...answer, outcome: e.currentTarget.value as Outcome })}
|
|
>
|
|
<option value="correct">Corretta</option>
|
|
<option value="partial">Parziale</option>
|
|
<option value="wrong">Sbagliata</option>
|
|
</select>
|
|
|
|
<div class="stack-h">
|
|
<button
|
|
onClick={() => {
|
|
if (answer.timestampRaw.trim() === '') {
|
|
alert('Inserisci un tempo valido')
|
|
return
|
|
}
|
|
|
|
sendAction({
|
|
...answer,
|
|
type: 'answer',
|
|
timestamp: parse(answer.timestampRaw, 'HH:mm:ss', new Date()).toISOString(),
|
|
})
|
|
}}
|
|
>
|
|
Invia risposta
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
type Receiver<T> = (key: string, cb: (data: T) => void) => void
|
|
|
|
export const SubmitActionJolly = ({
|
|
room,
|
|
sendAction,
|
|
onTeamQuestionIndex,
|
|
}: {
|
|
room: RoomData
|
|
sendAction: (action: Action) => void
|
|
onTeamQuestionIndex?: Receiver<{ team: string; question: string }>
|
|
}) => {
|
|
const groupsMap: Record<string, boolean> = {}
|
|
room.questions.forEach(question => {
|
|
groupsMap[question.group] = true
|
|
})
|
|
|
|
const groups = Object.keys(groupsMap)
|
|
|
|
const questionToGroup: Record<string, string> = {}
|
|
room.questions.forEach(question => {
|
|
questionToGroup[question.id] = question.group
|
|
})
|
|
|
|
const [answer, setAnswer] = useState<Omit<ActionJolly, 'timestamp'>>({
|
|
team: '',
|
|
group: '',
|
|
})
|
|
|
|
onTeamQuestionIndex?.('SubmitActionJolly', ({ team, question }) => {
|
|
console.log('onTeamQuestionIndex', team, question)
|
|
setAnswer(answer => ({ ...answer, team, group: questionToGroup[question] }))
|
|
})
|
|
|
|
return (
|
|
<div class="card tint-gold stack-v center">
|
|
<h3>Invia Jolly</h3>
|
|
|
|
<select
|
|
class="fill-w"
|
|
placeholder="Squadra..."
|
|
value={answer.team}
|
|
onInput={e => setAnswer({ ...answer, team: e.currentTarget.value })}
|
|
>
|
|
<option value="" disabled>
|
|
Seleziona squadra...
|
|
</option>
|
|
{room.teams.map((team, i) => (
|
|
<option value={team} key={i}>
|
|
{team}
|
|
</option>
|
|
))}
|
|
</select>
|
|
|
|
<select
|
|
class="fill-w"
|
|
placeholder="Gruppo..."
|
|
value={answer.group}
|
|
onInput={e => setAnswer({ ...answer, group: e.currentTarget.value })}
|
|
>
|
|
<option value="" disabled>
|
|
Seleziona gruppo...
|
|
</option>
|
|
{groups.map(group => (
|
|
<option value={group}>{group}</option>
|
|
))}
|
|
</select>
|
|
|
|
<button
|
|
onClick={() =>
|
|
sendAction({
|
|
...answer,
|
|
type: 'jolly',
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
}
|
|
>
|
|
Imposta jolly
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const SubmitAction = ({
|
|
room,
|
|
refreshRoom,
|
|
|
|
onTeamQuestionIndex,
|
|
}: {
|
|
room: Room
|
|
refreshRoom: () => void
|
|
onTeamQuestionIndex?: Receiver<{ team: string; question: string }>
|
|
}) => {
|
|
const sendAction = async (action: Action) => {
|
|
await sendJSON(`/api/room/${room.id}/action`, action)
|
|
refreshRoom()
|
|
}
|
|
|
|
if (!room) {
|
|
return <div>Loading...</div>
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<SubmitActionAnswer room={room} sendAction={sendAction} onTeamQuestionIndex={onTeamQuestionIndex} />
|
|
<SubmitActionAnswerAtTime room={room} sendAction={sendAction} onTeamQuestionIndex={onTeamQuestionIndex} />
|
|
<SubmitActionJolly room={room} sendAction={sendAction} onTeamQuestionIndex={onTeamQuestionIndex} />
|
|
</>
|
|
)
|
|
}
|