From 79cbccd8a9f16b01956a1132bf8cc1afcddc3373 Mon Sep 17 00:00:00 2001 From: Extroias <91105220+Extroias@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:41:01 -0300 Subject: [PATCH 1/9] fix: fixed previous breaking change on events --- .../bottom-bar-buttons/MotionsButton.tsx | 6 +- .../src/components/session/delegation-map.tsx | 6 +- frontend/src/schemas/types.gen.ts | 177 +++++++++++++----- 3 files changed, 131 insertions(+), 58 deletions(-) diff --git a/frontend/src/components/session/bottom-bar-buttons/MotionsButton.tsx b/frontend/src/components/session/bottom-bar-buttons/MotionsButton.tsx index 5de6b28..f9ee6c6 100644 --- a/frontend/src/components/session/bottom-bar-buttons/MotionsButton.tsx +++ b/frontend/src/components/session/bottom-bar-buttons/MotionsButton.tsx @@ -208,9 +208,9 @@ export default function TestButton() { { - if(motionKind === "moção") setSelectedMotion(value) - else if(motionKind === "questão") setSelectedQuestion(value) + onValueChange={(value : Motions | Questions | "") => { + if(motionKind === "moção") setSelectedMotion(value as Motions) + else if(motionKind === "questão") setSelectedQuestion(value as Questions | "") setDebateKind("") setUnmoderatedMinutes("") setSpeechCount("") diff --git a/frontend/src/components/session/delegation-map.tsx b/frontend/src/components/session/delegation-map.tsx index c4bfbc6..16eb8c9 100644 --- a/frontend/src/components/session/delegation-map.tsx +++ b/frontend/src/components/session/delegation-map.tsx @@ -16,7 +16,7 @@ import { import { useCommitteeStore } from "@/store/useCommitteeStore" import { CircleFlag } from 'react-circle-flags' import { sendMessage } from "@/context/SessionContext" -import { type ChairInsertQueueEvent, type MarkRollCallEvent, type SpeakerEvent , ChairEvents, RollCallChoice } from "@/schemas/types.gen" +import { type AddGslSpeakerEvent, type MarkRollCallEvent, type GrantFloorEvent , ChairEvents, RollCallChoice } from "@/schemas/types.gen" import { Tooltip, TooltipContent, @@ -160,10 +160,10 @@ export default function DelegationMap({ Ações sobre a Delegação - sendMessage({ type: ChairEvents.INSERT_QUEUE_EVENT, payload: { target: delegation.id } } satisfies ChairInsertQueueEvent)}> + sendMessage({ type: ChairEvents.ADD_GSL_SPEAKER_EVENT, payload: { representation_id: delegation.id } } satisfies AddGslSpeakerEvent)}> Colocar na Lista de Discursos - sendMessage({ type: ChairEvents.SPEAKER_EVENT, payload: { speaker_id: delegation.id } } satisfies SpeakerEvent)}> + sendMessage({ type: ChairEvents.GRANT_FLOOR_EVENT, payload: { representation_id: delegation.id } } satisfies GrantFloorEvent)}> Dar a palavra diff --git a/frontend/src/components/session/speaker-list.tsx b/frontend/src/components/session/speaker-list.tsx index b07c3b5..a740831 100644 --- a/frontend/src/components/session/speaker-list.tsx +++ b/frontend/src/components/session/speaker-list.tsx @@ -16,7 +16,7 @@ import { TooltipTrigger, } from "@/components/ui/tooltip" import { sendMessage } from "@/context/SessionContext" -import { type JoinQueueEvent, type SpeakerEvent, ChairEvents, DelegateEvents } from "@/schemas/types.gen" +import { type JoinQueueEvent, type NextSpeakerEvent, ChairEvents, DelegateEvents } from "@/schemas/types.gen" import { useSession } from "@/context/SessionContext" import { SessionRoles } from "@/schemas/types.gen" @@ -94,7 +94,7 @@ export default function SpeakerList() { variant="outline" className="flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap" disabled={waitingCount === 0} - onClick={() => sendMessage({ type: ChairEvents.SPEAKER_EVENT, payload: {} } satisfies SpeakerEvent)} + onClick={() => sendMessage({ type: ChairEvents.NEXT_SPEAKER_EVENT, payload: {} } satisfies NextSpeakerEvent)} > Proximo Proximo Orador diff --git a/frontend/src/schemas/types.gen.ts b/frontend/src/schemas/types.gen.ts index 3ea3f68..efaf9e0 100644 --- a/frontend/src/schemas/types.gen.ts +++ b/frontend/src/schemas/types.gen.ts @@ -4,6 +4,27 @@ export type ClientOptions = { baseUrl: 'http://localhost:8000' | (string & {}); }; +/** + * AddGslSpeakerEvent + */ +export type AddGslSpeakerEvent = { + /** + * Type + */ + type: 'AddGslSpeakerEvent'; + payload: AddGslSpeakerPayload; +}; + +/** + * AddGslSpeakerPayload + */ +export type AddGslSpeakerPayload = { + /** + * Representation Id + */ + representation_id: number; +}; + /** * AgendaItem */ @@ -50,7 +71,7 @@ export type BodyDummyCommitteesDummyGet = { /** * Types */ - types: SubmitMotionEvent | SubmitQuestionEvent | CastVoteEvent | AnswerRollCallEvent | JoinQueueEvent | LeaveQueueEvent | OpenSessionEvent | CloseSessionEvent | IncreaseTimerEvent | ToggleTimerEvent | OpenInformalVotingEvent | CloseProceduralVotingEvent | CloseInformalVotingEvent | ResolveMotionEvent | SpeakerEvent | SetAgendaEvent | SetAgendaItemEvent | MarkAgendaItemEvent | DeleteAgendaItemEvent | SetPhaseEvent | MarkRollCallEvent | CloseRollCallEvent | ChairInsertQueueEvent | MarkRollCallBulkEvent; + types: SubmitMotionEvent | SubmitQuestionEvent | CastVoteEvent | AnswerRollCallEvent | JoinQueueEvent | LeaveQueueEvent | LogMotionEvent | OpenSessionEvent | CloseSessionEvent | IncreaseTimerEvent | ToggleTimerEvent | OpenInformalVotingEvent | CloseProceduralVotingEvent | CloseInformalVotingEvent | FinishCaucusEvent | ResolveMotionEvent | NextSpeakerEvent | AddGslSpeakerEvent | GrantFloorEvent | SetAgendaEvent | SetAgendaItemEvent | MarkAgendaItemEvent | DeleteAgendaItemEvent | SetPhaseEvent | MarkRollCallEvent | CloseRollCallEvent | MarkRollCallBulkEvent; schemas: SessionLiveState; }; @@ -74,19 +95,22 @@ export const ChairEvents = { INCREASE_TIMER_EVENT: 'IncreaseTimerEvent', OPEN_INFORMAL_VOTING_EVENT: 'OpenInformalVotingEvent', RESOLVE_MOTION_EVENT: 'ResolveMotionEvent', + LOG_MOTION_EVENT: 'LogMotionEvent', CLOSE_PROCEDURAL_VOTING_EVENT: 'CloseProceduralVotingEvent', CLOSE_INFORMAL_VOTING_EVENT: 'CloseInformalVotingEvent', + FINISH_CAUCUS_EVENT: 'FinishCaucusEvent', SET_PHASE_EVENT: 'SetPhaseEvent', CLOSE_SESSION_EVENT: 'CloseSessionEvent', SET_AGENDA_ITEM_EVENT: 'SetAgendaItemEvent', MARK_AGENDA_ITEM_EVENT: 'MarkAgendaItemEvent', DELETE_AGENDA_ITEM_EVENT: 'DeleteAgendaItemEvent', SET_AGENDA: 'SetAgenda', - SPEAKER_EVENT: 'SpeakerEvent', + NEXT_SPEAKER_EVENT: 'NextSpeakerEvent', + ADD_GSL_SPEAKER_EVENT: 'AddGslSpeakerEvent', + GRANT_FLOOR_EVENT: 'GrantFloorEvent', MARK_ROLL_CALL_EVENT: 'MarkRollCallEvent', MARK_ROLL_CALL_BULK_EVENT: 'MarkRollCallBulkEvent', - CLOSE_ROLL_CALL_EVENT: 'CloseRollCallEvent', - INSERT_QUEUE_EVENT: 'InsertQueueEvent' + CLOSE_ROLL_CALL_EVENT: 'CloseRollCallEvent' } as const; /** @@ -94,20 +118,6 @@ export const ChairEvents = { */ export type ChairEvents = typeof ChairEvents[keyof typeof ChairEvents]; -/** - * ChairForceSpeakerPayload - */ -export type ChairForceSpeakerPayload = { - /** - * Speaker Id - */ - speaker_id?: number | null; - /** - * Seconds - */ - seconds?: number | null; -}; - /** * ChairIncreaseTimerPayload */ @@ -119,24 +129,34 @@ export type ChairIncreaseTimerPayload = { }; /** - * ChairInsertQueueEvent + * ChairMotionPayload + * + * Extended payload for motions. Used to log motions */ -export type ChairInsertQueueEvent = { +export type ChairMotionPayload = { + type: Motions; + debate_type?: DebateTypes | null; /** - * Type + * Total Duration Minutes */ - type: 'InsertQueueEvent'; - payload: ChairInsertQueuePayload; -}; - -/** - * ChairInsertQueuePayload - */ -export type ChairInsertQueuePayload = { + total_duration_minutes?: number | null; + /** + * Per Speaker Seconds + */ + per_speaker_seconds?: number | null; /** - * Target + * Target Topic */ - target: number; + target_topic?: string | null; + /** + * Details + */ + details?: string | null; + /** + * Representation Id + */ + representation_id: number; + decision: MotionDecision; }; /** @@ -391,6 +411,42 @@ export type EmptyPayload = { [key: string]: unknown; }; +/** + * FinishCaucusEvent + */ +export type FinishCaucusEvent = { + /** + * Type + */ + type: 'FinishCaucusEvent'; + payload: EmptyPayload; +}; + +/** + * GrantFloorEvent + */ +export type GrantFloorEvent = { + /** + * Type + */ + type: 'GrantFloorEvent'; + payload: GrantFloorPayload; +}; + +/** + * GrantFloorPayload + */ +export type GrantFloorPayload = { + /** + * Representation Id + */ + representation_id: number; + /** + * Seconds + */ + seconds?: number | null; +}; + /** * HTTPValidationError */ @@ -444,6 +500,17 @@ export type LeaveQueueEvent = { }; }; +/** + * LogMotionEvent + */ +export type LogMotionEvent = { + /** + * Type + */ + type: 'LogMotionEvent'; + payload: ChairMotionPayload; +}; + /** * MajorityTypes */ @@ -572,6 +639,20 @@ export type MotionContext = { details?: string | null; }; +/** + * MotionDecision + * + * Tracks decision for LogMotionEvent for chair + */ +export const MotionDecision = { ACCEPT: 'Accept', DENY: 'Deny' } as const; + +/** + * MotionDecision + * + * Tracks decision for LogMotionEvent for chair + */ +export type MotionDecision = typeof MotionDecision[keyof typeof MotionDecision]; + /** * Motions */ @@ -598,6 +679,17 @@ export const Motions = { */ export type Motions = typeof Motions[keyof typeof Motions]; +/** + * NextSpeakerEvent + */ +export type NextSpeakerEvent = { + /** + * Type + */ + type: 'NextSpeakerEvent'; + payload: EmptyPayload; +}; + /** * OpenInformalVotingEvent */ @@ -692,10 +784,7 @@ export type RollCallContext = { registry?: { [key: string]: RollCallChoice; }; - /** - * Current Delegation - */ - current_delegation?: number | null; + return_state?: States | null; }; /** @@ -785,12 +874,6 @@ export type SessionLiveState = { */ active_topic_index?: string | null; voting?: VotingContext | null; - /** - * Voting Choice - */ - voting_choice?: { - [key: string]: RollCallChoice; - } | null; roll_call: RollCallContext; /** * Has Veto Power @@ -866,17 +949,6 @@ export type SetPhaseEvent = { payload: ChairSetPhasePayload; }; -/** - * SpeakerEvent - */ -export type SpeakerEvent = { - /** - * Type - */ - type: 'SpeakerEvent'; - payload: ChairForceSpeakerPayload; -}; - /** * States */ @@ -891,6 +963,7 @@ export const States = { FINISHED: 'Finished', MODERATED_CAUCUS: 'Moderated Caucus', UNMODERATED_CAUCUS: 'Unmoderated Caucus', + TOUR_DE_TABLE: 'Tour de Table', VOTING_EXECUTION: 'Voting Execution', BETWEEN_DEBATES: 'Between Debates' } as const; From 1a2285acf400030c203160bcd1d5a0d145283328 Mon Sep 17 00:00:00 2001 From: Extroias <91105220+Extroias@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:26:44 -0300 Subject: [PATCH 4/9] fix: removed mark roll call restriction --- backend/app/session/engine.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/app/session/engine.py b/backend/app/session/engine.py index 02fe754..16cafcb 100644 --- a/backend/app/session/engine.py +++ b/backend/app/session/engine.py @@ -870,8 +870,9 @@ def handle_mark_roll_call( state: SessionLiveState, event: schemas.MarkRollCallEvent, actor: SessionActor ) -> SessionLiveState: require_chair(actor) - if state.current_state != States.ROLL_CALL or state.roll_call is None: - raise InvalidProceduralMove("Cannot mark roll call right now") + #removed these lines so chair can freely change the roll call + #if state.current_state != States.ROLL_CALL or state.roll_call is None: + # raise InvalidProceduralMove("Cannot mark roll call right now") if event.payload.delegation_id not in state.delegations: raise InvalidProceduralMove("Delegation does not exist") From e0bfde66fda5a98cc0910de754afc0465890cae9 Mon Sep 17 00:00:00 2001 From: Le-frances13 <100540487+Le-frances13@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:39:11 -0300 Subject: [PATCH 5/9] fix: small UI problems --- frontend/src/components/session/timer.tsx | 2 +- frontend/src/components/ui/flags.tsx | 8 +++++++- frontend/src/pages/Session.tsx | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/session/timer.tsx b/frontend/src/components/session/timer.tsx index 6693a67..e6184cf 100644 --- a/frontend/src/components/session/timer.tsx +++ b/frontend/src/components/session/timer.tsx @@ -15,7 +15,7 @@ export default function Timer() { const isChair = role===SessionRoles.CHAIR const delegations = useCommitteeStore((state) => state.delegations); const currentSpeaker = useCommitteeStore((state) => state.current_speaker); - const speaker = currentSpeaker !== null && currentSpeaker !== undefined ? delegations[currentSpeaker] : { + let speaker = currentSpeaker !== null && currentSpeaker !== undefined ? delegations[currentSpeaker] : { id: -1, seat: "", name: "Mesa", diff --git a/frontend/src/components/ui/flags.tsx b/frontend/src/components/ui/flags.tsx index 05bc728..c64d545 100644 --- a/frontend/src/components/ui/flags.tsx +++ b/frontend/src/components/ui/flags.tsx @@ -1,5 +1,5 @@ -import { useState } from "react" +import { useEffect, useState } from "react" import { cn } from "@/lib/utils" export default function Flags({ @@ -15,8 +15,14 @@ export default function Flags({ const [src, setSrc] = useState(baseSrc) const [usedFallback, setUsedFallback] = useState(false) + useEffect(() => { + setSrc(baseSrc) + setUsedFallback(false) + }, [baseSrc]) + return ( {code}} } - + From 109f8814c846bb0d4742d3ac0ab1a5e14f394bbb Mon Sep 17 00:00:00 2001 From: Le-frances13 <100540487+Le-frances13@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:39:35 -0300 Subject: [PATCH 6/9] Feat: Exit button takes to dashboard --- .../components/session/bottom-bar-buttons/ExitButton.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/session/bottom-bar-buttons/ExitButton.tsx b/frontend/src/components/session/bottom-bar-buttons/ExitButton.tsx index f74ee33..3750cef 100644 --- a/frontend/src/components/session/bottom-bar-buttons/ExitButton.tsx +++ b/frontend/src/components/session/bottom-bar-buttons/ExitButton.tsx @@ -10,7 +10,8 @@ import { AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog" -import { DoorOpen } from "lucide-react" +import { DoorOpen, } from "lucide-react" +import { Link } from "react-router-dom" export default function TestButton() { @@ -34,7 +35,9 @@ export default function TestButton() { Cancelar - Sair para a Dashboard + + Sair para a Dashboard + From ac4124c4963553058d50b6cb3df081b7947f2143 Mon Sep 17 00:00:00 2001 From: Le-frances13 <100540487+Le-frances13@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:40:40 -0300 Subject: [PATCH 7/9] fix: Next Speaker Button Event fix --- .../src/components/session/motions-list.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/session/motions-list.tsx b/frontend/src/components/session/motions-list.tsx index 4b6f7b9..16ef1eb 100644 --- a/frontend/src/components/session/motions-list.tsx +++ b/frontend/src/components/session/motions-list.tsx @@ -12,20 +12,20 @@ import { } from "@/components/ui/item" import { Badge } from "@/components/ui/badge" import Flags from "@/components/ui/flags" -import { sendMessage,useSession } from "@/context/SessionContext" -import { SessionRoles, ChairEvents, type ResolveMotionEvent} from "@/schemas/types.gen" +import { sendMessage, useSession } from "@/context/SessionContext" +import { SessionRoles, ChairEvents, type ResolveMotionEvent } from "@/schemas/types.gen" import { useCommitteeStore } from "@/store/useCommitteeStore" export default function MotionsList() { - const {role} = useSession() - const isChair = role===SessionRoles.CHAIR + const { role } = useSession() + const isChair = role === SessionRoles.CHAIR - const motions = useCommitteeStore((state)=>state.submitted_motions)! - const delegations = useCommitteeStore((state)=>state.delegations) + const motions = useCommitteeStore((state) => state.submitted_motions)! + const delegations = useCommitteeStore((state) => state.delegations) const sortedMotions = [...motions].sort((a, b) => { - if(b.priority !== a.priority) return b.priority! - a.priority! + if (b.priority !== a.priority) return b.priority! - a.priority! return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); }) @@ -42,9 +42,9 @@ export default function MotionsList() {

{new Date(motion.timestamp).toLocaleTimeString('pt-BR', { - hour: '2-digit', - minute: '2-digit' -})}

+ hour: '2-digit', + minute: '2-digit' + })}
@@ -58,9 +58,9 @@ export default function MotionsList() { {isChair && (
+ onClick={() => sendMessage({ type: ChairEvents.RESOLVE_MOTION_EVENT, payload: { motion_id: motion.id!, action: true } } satisfies ResolveMotionEvent)}>Acatar + onClick={() => sendMessage({ type: ChairEvents.RESOLVE_MOTION_EVENT, payload: { motion_id: motion.id!, action: false } } satisfies ResolveMotionEvent)}>Rejeitar
)} From 39a4ff29d47afebd2cc2eb945d2e7aa600958e33 Mon Sep 17 00:00:00 2001 From: Le-frances13 <100540487+Le-frances13@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:41:20 -0300 Subject: [PATCH 8/9] feat: Live update of frontend for dev --- frontend/vite.config.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5b6048f..511f4d2 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -14,4 +14,14 @@ export default defineConfig({ "@": path.resolve(__dirname, "./src"), }, }, + server: { + watch: { + usePolling: true, // Alternative to setting environment variables + }, + host: true, // Exposes the server to the local network inside Docker + strictPort: true, + hmr: { + clientPort: 5173, // Forces the browser to connect to the exposed host port + }, + }, }) From 8c3715c28a7f93b111e9fa3c0590f529d6265427 Mon Sep 17 00:00:00 2001 From: Le-frances13 <100540487+Le-frances13@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:42:05 -0300 Subject: [PATCH 9/9] feat: Idiot proofing edit quorum button --- frontend/src/components/session/manual-quorum.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/session/manual-quorum.tsx b/frontend/src/components/session/manual-quorum.tsx index 5c15ff4..717cb5a 100644 --- a/frontend/src/components/session/manual-quorum.tsx +++ b/frontend/src/components/session/manual-quorum.tsx @@ -21,7 +21,7 @@ import { } from "@/components/ui/item" import { Separator } from "@/components/ui/separator" import { CircleFlag } from 'react-circle-flags' -import { type MarkRollCallBulkEvent, ChairEvents, RollCallChoice } from "@/schemas/types.gen" +import { type MarkRollCallBulkEvent, ChairEvents, RollCallChoice, States } from "@/schemas/types.gen" export default function ManualQuorum() { @@ -41,13 +41,13 @@ export default function ManualQuorum() { setTempQuorum(nextQuorum) } - + const currentState = useCommitteeStore((state) => state.current_state) return (
-