1- import { useState } from 'react' ;
2- import { CharacterId , CHARACTERS } from './characters' ;
1+ import { useMemo , useState } from 'react' ;
2+ import { CharacterId , CHARACTERS , Reminder } from './characters' ;
33import ReminderToken from './reminder-token' ;
44import Modal from 'components/modal' ;
55import { BotcPlayer } from './blood-on-the-clocktower-game' ;
66import Button from 'components/input/button' ;
77import Switch from 'components/input/switch' ;
8+ import Divider from 'components/divider' ;
89
9- type SelectMode = 'none' | 'reminder' | ' player';
10+ type SelectMode = 'none' | 'player' ;
1011
1112interface BotcActionsModalProps {
1213 open : boolean ;
@@ -37,16 +38,19 @@ const BotcActionsModal = ({
3738 const [ addMultipleReminders , setAddMultipleReminders ] = useState ( false ) ;
3839
3940 const characters = new Set ( players . map ( ( p ) => p . characterId ) ) ;
40- const reminderTokens = (
41- showAllReminders
42- ? allCharacters
43- : allCharacters . filter ( ( id ) => characters . has ( id ) )
44- ) . flatMap (
45- ( id ) =>
46- CHARACTERS [ id ] . reminderTokens ?. map ( ( reminderText ) => ( {
47- id,
48- reminderText,
49- } ) ) ?? [ ] ,
41+ const reminderTokens = useMemo (
42+ ( ) =>
43+ ( showAllReminders
44+ ? allCharacters
45+ : allCharacters . filter ( ( id ) => characters . has ( id ) )
46+ ) . flatMap (
47+ ( id ) =>
48+ CHARACTERS [ id ] . reminderTokens ?. map ( ( reminderText ) => ( {
49+ characterId : id ,
50+ message : reminderText ,
51+ } ) ) ?? [ ] ,
52+ ) ,
53+ [ showAllReminders , allCharacters , characters ] ,
5054 ) ;
5155
5256 const killOrRevivePlayer = ( ) => {
@@ -60,13 +64,30 @@ const BotcActionsModal = ({
6064
6165 const canKill = character . reminderTokens ?. includes ( 'Killed by' ) ?? false ;
6266
67+ const reminderHash = ( reminder : Reminder ) =>
68+ `id:${ reminder . characterId } ,message:${ reminder . message } ` ;
69+ const alreadyAdded = new Set ( player . reminders . map ( reminderHash ) ) ;
70+
71+ const filterReminderTokens = ( reminder : Reminder ) => {
72+ if ( alreadyAdded . has ( reminderHash ( reminder ) ) ) {
73+ return false ;
74+ }
75+
76+ if (
77+ reminder . message === 'No ability' &&
78+ reminder . characterId !== player . characterId
79+ ) {
80+ return false ;
81+ }
82+
83+ return true ;
84+ } ;
85+
6386 return (
6487 < Modal
6588 title = {
6689 selectMode === 'none'
6790 ? character . name + ( player . name ? ` (${ player . name } )` : '' )
68- : selectMode === 'reminder'
69- ? 'Add reminder token'
7091 : 'Select player'
7192 }
7293 withCloseButton
@@ -86,31 +107,64 @@ const BotcActionsModal = ({
86107 < Button fullWidth onClick = { killOrRevivePlayer } >
87108 { player . isAlive ? 'Kill' : 'Revive' } this player
88109 </ Button >
89- < Button fullWidth disabled = { ! canKill } onClick = { killOrRevivePlayer } >
110+ < Button fullWidth disabled = { ! canKill } >
90111 Kill another player
91112 </ Button >
92- < Button
93- fullWidth
94- onClick = { ( ) => {
95- setSelectMode ( 'reminder' ) ;
96- } }
97- >
98- Add reminder
99- </ Button >
113+ </ div >
114+ < Divider />
115+ < div className = 'flex flex-col gap-2 px-2' >
116+ < div className = 'flex flex-col gap-4 md:flex-row' >
117+ < h4 > Add Reminder</ h4 >
118+ < Switch
119+ label = 'Show tokens not in play'
120+ value = { showAllReminders }
121+ onChange = { setShowAllReminders }
122+ />
123+ < Switch
124+ label = 'Add multiple tokens'
125+ value = { addMultipleReminders }
126+ onChange = { setAddMultipleReminders }
127+ />
128+ </ div >
129+ < div className = 'grid grid-cols-3 gap-4 md:grid-cols-5 lg:grid-cols-7' >
130+ { reminderTokens
131+ . filter ( filterReminderTokens )
132+ . map ( ( { characterId, message } ) => (
133+ < ReminderToken
134+ key = { characterId + message }
135+ onClick = { ( ) => {
136+ const newPlayers = players . slice ( ) ;
137+ newPlayers [ playerIndex ] ?. reminders . push ( {
138+ characterId,
139+ message,
140+ } ) ;
141+ setPlayers ( newPlayers ) ;
142+ if ( ! addMultipleReminders ) {
143+ setOpen ( false ) ;
144+ }
145+ } }
146+ characterId = { characterId }
147+ text = { message }
148+ />
149+ ) ) }
150+ </ div >
100151 </ div >
101152 { player . reminders . length > 0 && (
102153 < >
103- < h5 > Added reminders (click to remove)</ h5 >
104- < div className = 'grid grid-cols-4 gap-y -2 md:grid-cols-5 lg:grid-cols-7' >
154+ < h4 > Added reminders (click to remove)</ h4 >
155+ < div className = 'grid grid-cols-3 gap-4 px -2 md:grid-cols-5 lg:grid-cols-7' >
105156 { player . reminders . map ( ( reminder , i ) => (
106157 < ReminderToken
107- key = { `index :${ playerIndex } ${ reminder . characterId } ${ reminder . message } ` }
158+ key = { `player :${ playerIndex } ${ reminder . characterId } ${ reminder . message } ` }
108159 characterId = { reminder . characterId }
109160 text = { reminder . message }
110161 onClick = { ( ) => {
111162 const newPlayers = players . slice ( ) ;
112163 newPlayers [ playerIndex ] ?. reminders . splice ( i , 1 ) ;
113164 setPlayers ( newPlayers ) ;
165+ if ( ! addMultipleReminders ) {
166+ setOpen ( false ) ;
167+ }
114168 } }
115169 />
116170 ) ) }
@@ -119,50 +173,6 @@ const BotcActionsModal = ({
119173 ) }
120174 </ div >
121175 ) }
122- { selectMode === 'reminder' && (
123- < div className = 'flex flex-col gap-4' >
124- < div className = 'flex gap-4' >
125- < Switch
126- label = 'Show all'
127- value = { showAllReminders }
128- onChange = { setShowAllReminders }
129- />
130- < Switch
131- label = 'Add multiple'
132- value = { addMultipleReminders }
133- onChange = { setAddMultipleReminders }
134- />
135- </ div >
136- < div className = 'grid grid-cols-4 gap-y-2 md:grid-cols-5 lg:grid-cols-7' >
137- { reminderTokens . map ( ( { id, reminderText } ) => (
138- < ReminderToken
139- key = { id + reminderText }
140- onClick = { ( ) => {
141- const newPlayers = players . slice ( ) ;
142- newPlayers [ playerIndex ] ?. reminders . push ( {
143- characterId : id ,
144- message : reminderText ,
145- } ) ;
146- setPlayers ( newPlayers ) ;
147- if ( ! addMultipleReminders ) {
148- setOpen ( false ) ;
149- setSelectMode ( 'none' ) ;
150- }
151- } }
152- characterId = { id }
153- text = { reminderText }
154- />
155- ) ) }
156- </ div >
157- < Button
158- onClick = { ( ) => {
159- setSelectMode ( 'none' ) ;
160- } }
161- >
162- Cancel
163- </ Button >
164- </ div >
165- ) }
166176 { selectMode === 'player' && 'test' }
167177 </ Modal >
168178 ) ;
0 commit comments