Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export const VERSION = '1.6.2'
export const VERSION = '1.7.0'

export const RequiredVersions = {
controller: VERSION,
tts: '2.0.0',
piper: '1.3.0',
sounder: '2.1.0',
sounder: '2.4.0',
button: '1.0.0'
}

Expand Down
14 changes: 5 additions & 9 deletions app/lib/settings.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,30 @@ import {asyncForEach} from '@arcath/utils'
import {getPrisma} from './prisma.server'

type SettingKey =
| 'lockdownEntrySound'
| 'lockdownExitSound'
| 'lockdownRepeat'
| 'lockdownExitRepeat'
| 'lockdownMode'
| 'lockdownRepeatRingerWire'
| 'lockdownRepetitions'
| 'password'
| 'ttsSpeed'
| 'enrollUrl'
| 'controlPointKey'
| 'ttsLastSeen'
| 'workerLastSeen'
| 'lockdownEntrySequence'
| 'lockdownExitSequence'

export const DEFAULT_SETTINGS: {[setting in SettingKey]: string} = {
lockdownEntrySound: '',
lockdownExitSound: '',
lockdownRepeat: '5',
lockdownExitRepeat: '2',
lockdownRepeatRingerWire: '0',
lockdownMode: '0',
lockdownRepetitions: '4',
password: 'bell',
ttsSpeed: '1',
enrollUrl: 'http://controller:3000',
controlPointKey: '',
ttsLastSeen: '"1970-01-01T23:00:00.000Z"',
workerLastSeen: '"1970-01-01T23:00:00.000Z"'
workerLastSeen: '"1970-01-01T23:00:00.000Z"',
lockdownEntrySequence: '[]',
lockdownExitSequence: '[]'
}

export const getSetting = async (setting: SettingKey) => {
Expand Down
6 changes: 6 additions & 0 deletions app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ export const en = {
'lockdown.field.entrySound.label': 'Lockdown start sound',
'lockdown.field.entrySound.helper':
'Sound used to start lockdown and for repetitions.',
'lockdown.field.entrySequence.label': 'Lockdown Entry Sequence',
'lockdown.field.entrySequence.helper':
'The sequence that is run when lockdown starts and on any repetitions.',
'lockdown.field.exitSequence.label': 'Lockdown Exit Sequence',
'lockdown.field.exitSequence.helper':
'The sequence that is run when lockdown ends.',
'lockdown.field.exitSound.label': 'Lockdown end sound',
'lockdown.field.exitSound.helper': 'Sound used to end lockdown.',
'lockdown.field.startCount.label': 'Lockdown start count',
Expand Down
2 changes: 1 addition & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const AppContent = () => {
</SidebarLink>
</div>
<div className="text-sm text-gray-400 p-2 text-center">
&copy; Open School Bell 2025 <br />
&copy; Open School Bell 2026 <br />
OSB {VERSION}
</div>
</div>
Expand Down
121 changes: 30 additions & 91 deletions app/routes/lockdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {Page, FormElement, Actions} from '~/lib/ui'
import {useTranslation} from '~/lib/i18n'
import {translate} from '~/lib/i18n.shared'
import {getRootI18n} from '~/lib/i18n.meta'
import {SequenceBuilder} from '~/lib/sequence-builder'

export const meta: MetaFunction = ({matches}) => {
const {messages} = getRootI18n(matches)
Expand All @@ -31,19 +32,15 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
const {
lockdownMode,
lockdownRepeat,
lockdownExitRepeat,
lockdownEntrySound,
lockdownExitSound,
lockdownRepeatRingerWire,
lockdownRepetitions
lockdownEntrySequence,
lockdownExitSequence
} = await getSettings([
'lockdownEntrySound',
'lockdownMode',
'lockdownRepeat',
'lockdownExitRepeat',
'lockdownExitSound',
'lockdownRepeatRingerWire',
'lockdownRepetitions'
'lockdownEntrySequence',
'lockdownExitSequence'
])

const prisma = getPrisma()
Expand All @@ -53,49 +50,37 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
return {
lockdownMode,
lockdownRepeat,
lockdownExitRepeat,
lockdownEntrySound,
lockdownExitSound,
lockdownRepeatRingerWire,
lockdownRepetitions,
lockdownEntrySequence,
lockdownExitSequence,
sounds
}
}

export const action = async ({request}: ActionFunctionArgs) => {
const formData = await request.formData()

const lockdownEntrySound = formData.get('lockdownEntrySound') as
| string
| undefined
const lockdownExitSound = formData.get('lockdownExitSound') as
| string
| undefined
const lockdownRepetitions = formData.get('lockdownRepetitions') as
const lockdownRepeat = formData.get('lockdownRepeat') as string | undefined
const lockdownEntrySequence = formData.get('lockdownEntrySequence') as
| string
| undefined
const lockdownExitRepeat = formData.get('lockdownExitRepeat') as
const lockdownExitSequence = formData.get('lockdownExitSequence') as
| string
| undefined
const lockdownRepeat = formData.get('lockdownRepeat') as string | undefined
const lockdownRepeatRingerWire = !!(formData.get(
'lockdownRepeatRingerWire'
) as string | undefined)
? '1'
: '0'

invariant(lockdownEntrySound)
invariant(lockdownExitSound)
invariant(lockdownRepetitions)
invariant(lockdownRepeat)
invariant(lockdownExitRepeat)
invariant(lockdownEntrySequence)
invariant(lockdownExitSequence)

await setSetting('lockdownEntrySound', lockdownEntrySound)
await setSetting('lockdownExitSound', lockdownExitSound)
await setSetting('lockdownRepetitions', lockdownRepetitions)
await setSetting('lockdownExitRepeat', lockdownExitRepeat)
await setSetting('lockdownRepeat', lockdownRepeat)
await setSetting('lockdownRepeatRingerWire', lockdownRepeatRingerWire)
await setSetting('lockdownEntrySequence', lockdownEntrySequence)
await setSetting('lockdownExitSequence', lockdownExitSequence)

return redirect('/lockdown')
}
Expand All @@ -104,11 +89,9 @@ const Lockdown = () => {
const {
lockdownMode,
lockdownRepeat,
lockdownExitRepeat,
lockdownEntrySound,
lockdownExitSound,
lockdownRepeatRingerWire,
lockdownRepetitions,
lockdownEntrySequence,
lockdownExitSequence,
sounds
} = useLoaderData<typeof loader>()
const {t} = useTranslation()
Expand All @@ -123,64 +106,20 @@ const Lockdown = () => {
: t('lockdown.status.inactive')}{' '}
</div>
<form method="post">
<FormElement
label={t('lockdown.field.entrySound.label')}
helperText={t('lockdown.field.entrySound.helper')}
>
<select
className={INPUT_CLASSES}
name="lockdownEntrySound"
defaultValue={lockdownEntrySound}
>
{sounds.map(({id, name}) => {
return (
<option key={id} value={id}>
{name}
</option>
)
})}
</select>
</FormElement>
<FormElement
label={t('lockdown.field.exitSound.label')}
helperText={t('lockdown.field.exitSound.helper')}
>
<select
className={INPUT_CLASSES}
name="lockdownExitSound"
defaultValue={lockdownExitSound}
>
{sounds.map(({id, name}) => {
return (
<option key={id} value={id}>
{name}
</option>
)
})}
</select>
</FormElement>
<FormElement
label={t('lockdown.field.startCount.label')}
helperText={t('lockdown.field.startCount.helper')}
>
<input
type="number"
name="lockdownRepetitions"
className={INPUT_CLASSES}
defaultValue={lockdownRepetitions}
/>
</FormElement>
<FormElement
label={t('lockdown.field.exitCount.label')}
helperText={t('lockdown.field.exitCount.helper')}
>
<input
type="number"
name="lockdownExitRepeat"
className={INPUT_CLASSES}
defaultValue={lockdownExitRepeat}
/>
</FormElement>
<SequenceBuilder
sounds={sounds}
initialQueue={JSON.parse(lockdownEntrySequence)}
name="lockdownEntrySequence"
label={t('lockdown.field.entrySequence.label')}
helperText={t('lockdown.field.entrySequence.helper')}
/>
<SequenceBuilder
sounds={sounds}
initialQueue={JSON.parse(lockdownExitSequence)}
name="lockdownExitSequence"
label={t('lockdown.field.exitSequence.label')}
helperText={t('lockdown.field.exitSequence.helper')}
/>
<FormElement
label={t('lockdown.field.repeatInterval.label')}
helperText={t('lockdown.field.repeatInterval.helper')}
Expand Down
29 changes: 8 additions & 21 deletions app/routes/sounder-api.get-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,17 @@ export const action = async ({request}: ActionFunctionArgs) => {
const {
lockdownMode,
lockdownRepeat,
lockdownExitRepeat,
lockdownEntrySound,
lockdownExitSound,
lockdownRepeatRingerWire,
lockdownRepetitions
lockdownEntrySequence,
lockdownExitSequence,
lockdownRepeatRingerWire
} = await getSettings([
'lockdownEntrySound',
'lockdownEntrySequence',
'lockdownExitSequence',
'lockdownMode',
'lockdownRepeat',
'lockdownExitSound',
'lockdownRepeatRingerWire',
'lockdownRepetitions',
'lockdownExitRepeat'
'lockdownRepeatRingerWire'
])

const entrySound = await prisma.audio.findFirstOrThrow({
where: {id: lockdownEntrySound}
})
const exitSound = await prisma.audio.findFirstOrThrow({
where: {id: lockdownExitSound}
})

return Response.json({
id: sounder.id,
name: sounder.name,
Expand All @@ -70,10 +59,8 @@ export const action = async ({request}: ActionFunctionArgs) => {
),
lockdown: {
enable: lockdownMode === '1',
entrySound: entrySound.id,
exitSound: exitSound.id,
times: parseInt(lockdownRepetitions),
exitTimes: parseInt(lockdownExitRepeat),
entrySequence: lockdownEntrySequence,
exitSequence: lockdownExitSequence,
interval: parseInt(lockdownRepeat),
repeatRingerWire: lockdownRepeatRingerWire === '1'
}
Expand Down
85 changes: 85 additions & 0 deletions prisma/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,91 @@ const main = async () => {
})
})
)

const lockdownSettings = await prisma.setting.findMany({
where: {
key: {
in: [
'lockdownEntrySound',
'lockdownExitSound',
'lockdownExitRepeat',
'lockdownRepetitions'
]
}
}
})

if (lockdownSettings.length > 0) {
const lockdownEntrySound = lockdownSettings.reduce((v, {key, value}) => {
if (v) return v
if (key === 'lockdownEntrySound') return value
return undefined
}, undefined)

const lockdownRepetitions = lockdownSettings.reduce((v, {key, value}) => {
if (v) return v
if (key === 'lockdownRepetitions') return value
return undefined
}, undefined)

if (lockdownEntrySound && lockdownRepetitions) {
const entrySequence = []

let i = 0
while (i < parseInt(lockdownRepetitions)) {
entrySequence.push(lockdownEntrySound)
i++
}

await prisma.setting.upsert({
where: {key: 'lockdownEntrySequence'},
create: {
key: 'lockdownEntrySequence',
value: JSON.stringify(entrySequence)
},
update: {value: JSON.stringify(entrySequence)}
})

await prisma.setting.deleteMany({
where: {key: {in: ['lockdownEntrySound', 'lockdownRepetitions']}}
})
}

const lockdownExitSound = lockdownSettings.reduce((v, {key, value}) => {
if (v) return v
if (key === 'lockdownExitSound') return value
return undefined
}, undefined)

const lockdownExitRepeat = lockdownSettings.reduce((v, {key, value}) => {
if (v) return v
if (key === 'lockdownExitRepeat') return value
return undefined
}, undefined)

if (lockdownExitSound && lockdownExitRepeat) {
const exitSequence = []

let i = 0
while (i < parseInt(lockdownExitRepeat)) {
exitSequence.push(lockdownExitSound)
i++
}

await prisma.setting.upsert({
where: {key: 'lockdownExitSequence'},
create: {
key: 'lockdownExitSequence',
value: JSON.stringify(exitSequence)
},
update: {value: JSON.stringify(exitSequence)}
})

await prisma.setting.deleteMany({
where: {key: {in: ['lockdownExitSound', 'lockdownExitRepeat']}}
})
}
}
}

main()
Loading