Skip to content

Commit

Permalink
wip: Osasuorituksen lisääminen
Browse files Browse the repository at this point in the history
  • Loading branch information
ilkkahanninen committed Dec 9, 2024
1 parent b248178 commit 20b893a
Show file tree
Hide file tree
Showing 8 changed files with 645 additions and 124 deletions.
60 changes: 52 additions & 8 deletions web/app/components-v2/opiskeluoikeus/OppiaineTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { suoritusValmis } from '../../util/suoritus'
import { useBooleanState } from '../../util/useBooleanState'
import { notUndefined } from '../../util/util'
import { KeyValueRow, KeyValueTable } from '../containers/KeyValueTable'
import { FlatButton } from '../controls/FlatButton'
import { IconButton } from '../controls/IconButton'
import { FormModel } from '../forms/FormModel'
import { CHARCODE_REMOVE } from '../texts/Icon'
Expand All @@ -24,17 +25,21 @@ export type OppiainePäätasonSuoritus = IBPäätasonSuoritus

export type OppiaineOsasuoritus = OsasuoritusOf<OppiainePäätasonSuoritus>

export type OppiaineTableProps = {
export type OppiaineTableProps<T> = {
form: FormModel<IBOpiskeluoikeus>
suoritus: OppiainePäätasonSuoritus
onDelete: (index: number) => void
addOsasuoritusDialog: AddOppiaineenOsasuoritusDialog<T>
onAddOsasuoritus: (oppiaineIndex: number, osasuoritus: T) => void
}

export const OppiaineTable: React.FC<OppiaineTableProps> = ({
export const OppiaineTable = <T,>({
suoritus,
form,
onDelete
}) => {
onDelete,
addOsasuoritusDialog,
onAddOsasuoritus
}: OppiaineTableProps<T>) => {
const oppiaineet = suoritus.osasuoritukset || []

return oppiaineet.length === 0 ? null : (
Expand All @@ -55,28 +60,55 @@ export const OppiaineTable: React.FC<OppiaineTableProps> = ({
oppiaine={oppiaine}
form={form}
onDelete={() => onDelete(i)}
addOsasuoritusDialog={addOsasuoritusDialog}
onAddOsasuoritus={(osasuoritus) => onAddOsasuoritus(i, osasuoritus)}
/>
))}
</tbody>
</table>
)
}

type OppiaineRowProps = {
export type OppiaineRowProps<T> = {
form: FormModel<IBOpiskeluoikeus>
oppiaine: OppiaineOsasuoritus
addOsasuoritusDialog: AddOppiaineenOsasuoritusDialog<T>
onAddOsasuoritus: (t: T) => void
onDelete: () => void
}

const OppiaineRow: React.FC<OppiaineRowProps> = ({
export type AddOppiaineenOsasuoritusDialog<T> = React.FC<{
oppiaine: OppiaineOsasuoritus
onAdd: (t: T) => void
onClose: () => void
}>

const OppiaineRow = <T,>({
oppiaine,
form,
onDelete
}) => {
onDelete,
addOsasuoritusDialog,
onAddOsasuoritus
}: OppiaineRowProps<T>) => {
const kurssit = oppiaine.osasuoritukset || []
const kurssejaYhteensä = sum(
kurssit.map((k) => k.koulutusmoduuli.laajuus?.arvo || 0)
)
const [
addOsasuoritusDialogVisible,
showAddOsasuoritusDialog,
hideAddOsasuoritusDialog
] = useBooleanState(false)

const AddOsasuoritusDialog = addOsasuoritusDialog

const addOsasuoritus = useCallback(
(osasuoritus: T) => {
onAddOsasuoritus(osasuoritus)
hideAddOsasuoritusDialog()
},
[hideAddOsasuoritusDialog, onAddOsasuoritus]
)

return (
<tr>
Expand All @@ -91,6 +123,11 @@ const OppiaineRow: React.FC<OppiaineRowProps> = ({
{kurssit.map((kurssi, index) => (
<Kurssi key={index} kurssi={kurssi} oppiaine={oppiaine} />
))}
{form.editMode && (
<FlatButton onClick={showAddOsasuoritusDialog}>
{t('Lisää osasuoritus')}
</FlatButton>
)}
</div>
</td>
<td className="OppiaineRow__laajuus">{kurssejaYhteensä}</td>
Expand All @@ -104,6 +141,13 @@ const OppiaineRow: React.FC<OppiaineRowProps> = ({
onClick={onDelete}
testId="delete"
/>
{addOsasuoritusDialogVisible && (
<AddOsasuoritusDialog
oppiaine={oppiaine}
onAdd={addOsasuoritus}
onClose={hideAddOsasuoritusDialog}
/>
)}
</td>
)}
</tr>
Expand Down
174 changes: 63 additions & 111 deletions web/app/ib/IBEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,20 @@ import {
} from '../components-v2/containers/Modal'
import { FlatButton } from '../components-v2/controls/FlatButton'
import { RaisedButton } from '../components-v2/controls/RaisedButton'
import { SelectOption } from '../components-v2/controls/Select'
import { FormModel, useForm } from '../components-v2/forms/FormModel'
import { AdaptedOpiskeluoikeusEditorProps } from '../components-v2/interoperability/useUiAdapter'
import { Spacer } from '../components-v2/layout/Spacer'
import { OpiskeluoikeusTitle } from '../components-v2/opiskeluoikeus/OpiskeluoikeusTitle'
import { OppiaineTable } from '../components-v2/opiskeluoikeus/OppiaineTable'
import {
PaikallinenKoulutus,
PaikallinenKoulutusFields
} from '../components-v2/opiskeluoikeus/PaikallinenKoulutusFields'
AddOppiaineenOsasuoritusDialog,
OppiaineTable
} from '../components-v2/opiskeluoikeus/OppiaineTable'
import { SuorituksenVahvistusField } from '../components-v2/opiskeluoikeus/SuorituksenVahvistus'
import { localize, t } from '../i18n/i18n'
import { IBOpiskeluoikeus } from '../types/fi/oph/koski/schema/IBOpiskeluoikeus'
import { IBTutkinto } from '../types/fi/oph/koski/schema/IBTutkinto'
import { isLaajuusKursseissa } from '../types/fi/oph/koski/schema/LaajuusKursseissa'
import { LukionOpiskeluoikeusjakso } from '../types/fi/oph/koski/schema/LukionOpiskeluoikeusjakso'
import { PaikallinenKoodi } from '../types/fi/oph/koski/schema/PaikallinenKoodi'
import { PreIBKoulutusmoduuli2015 } from '../types/fi/oph/koski/schema/PreIBKoulutusmoduuli2015'
import { PreIBKoulutusmoduuli2019 } from '../types/fi/oph/koski/schema/PreIBKoulutusmoduuli2019'
import { PreIBSuorituksenOsasuoritus2015 } from '../types/fi/oph/koski/schema/PreIBSuorituksenOsasuoritus2015'
Expand All @@ -45,19 +42,19 @@ import {
ibKoulutusNimi,
IBPäätasonSuoritusTiedot
} from './IBPaatasonSuoritusTiedot'
import { UusiPreIB2015OppiaineDialog } from './dialogs/UusiPreIB2015OppiaineDialog'
import { createPreIBKurssinSuoritus2015 } from './oppiaineet/preIBKurssi2015'
import {
PaikallinenKey,
preIB2015Oppiainekategoriat,
useAineryhmäOptions,
useKielivalikoimaOptions,
useMatematiikanOppimääräOptions,
usePreIBTunnisteOptions,
useÄidinkielenKieliOptions
useLukiokurssinTyypit,
useLukioValtakunnallisetKurssit2015Options
} from './state/options'
import { useIBOsasuoritusState } from './state/osasuoritusState'
import {
PreIBOppiaineTunniste,
useUusiPreIB2015OppiaineState
} from './state/preIBOppiaine'
PaikallinenKoulutus,
PaikallinenKoulutusFields
} from '../components-v2/opiskeluoikeus/PaikallinenKoulutusFields'
import { PaikallinenKoodi } from '../types/fi/oph/koski/schema/PaikallinenKoodi'
import { PreIBKurssinSuoritus2015 } from '../types/fi/oph/koski/schema/PreIBKurssinSuoritus2015'

export type IBEditorProps = AdaptedOpiskeluoikeusEditorProps<IBOpiskeluoikeus>

Expand Down Expand Up @@ -112,6 +109,20 @@ const IBPäätasonSuoritusEditor: React.FC<
[form, päätasonSuoritus.path]
)

const addOsasuoritus = useCallback(
(oppiaineIndex: number, osasuoritus: PreIBKurssinSuoritus2015) => {
form.updateAt(
päätasonSuoritus.path
.prop('osasuoritukset')
.optional()
.at(oppiaineIndex)
.prop('osasuoritukset') as any,
appendOptional(osasuoritus)
)
},
[form, päätasonSuoritus.path]
)

return (
<EditorContainer
form={form}
Expand Down Expand Up @@ -140,6 +151,8 @@ const IBPäätasonSuoritusEditor: React.FC<
suoritus={päätasonSuoritus.suoritus}
form={form}
onDelete={deleteOppiaine}
addOsasuoritusDialog={AddIBOsasuoritusDialog}
onAddOsasuoritus={addOsasuoritus}
/>

{kurssejaYhteensä !== null && (
Expand Down Expand Up @@ -186,36 +199,16 @@ const useSuoritetutKurssitYhteensä = (
return isEmpty(laajuudet) ? null : sum(laajuudet)
}

type UusiPreIB2015OppiaineDialogProps = {
päätasonSuoritus: PäätasonSuoritusOf<IBOpiskeluoikeus>
onClose: () => void
onSubmit: (oppiaine: PreIBSuorituksenOsasuoritus2015) => void
}
const AddIBOsasuoritusDialog: AddOppiaineenOsasuoritusDialog<
PreIBKurssinSuoritus2015
> = ({ onAdd, ...props }) => {
const koulutus = props.oppiaine.koulutusmoduuli
const state = useIBOsasuoritusState(koulutus, createPreIBKurssinSuoritus2015)

const UusiPreIB2015OppiaineDialog: React.FC<
UusiPreIB2015OppiaineDialogProps
> = (props) => {
const state = useUusiPreIB2015OppiaineState()
const tunnisteet = usePreIBTunnisteOptions(
preIB2015Oppiainekategoriat,
props.päätasonSuoritus
)
const kielet = useKielivalikoimaOptions(state.kieli.visible)
const matematiikanOppimäärät = useMatematiikanOppimääräOptions(
state.matematiikanOppimäärä.visible
)
const ryhmät = useAineryhmäOptions(state.ryhmä.visible)
const äidinkielenKielet = useÄidinkielenKieliOptions(
state.äidinkielenKieli.visible
)

const onTunniste = useCallback(
(option?: SelectOption<PreIBOppiaineTunniste>) => {
state.tunniste.set(option?.value)
state.paikallinenTunniste.setVisible(option?.key === PaikallinenKey)
},
[state.paikallinenTunniste, state.tunniste]
const lukioTunnisteet = useLukioValtakunnallisetKurssit2015Options(
state.lukioTunniste.visible
)
const kurssityypit = useLukiokurssinTyypit(state.lukiokurssinTyyppi.visible)

const onPaikallinenKoulutus = useCallback(
(paikallinen?: PaikallinenKoulutus) => {
Expand All @@ -226,97 +219,56 @@ const UusiPreIB2015OppiaineDialog: React.FC<
nimi: localize(paikallinen.nimi)
})
)
state.paikallinenKuvaus.set(localize(paikallinen.kuvaus))
state.kuvaus.set(localize(paikallinen.kuvaus))
}
},
[state.paikallinenKuvaus, state.paikallinenTunniste]
[state.kuvaus, state.paikallinenTunniste]
)

const onSubmit = useCallback(() => {
if (state.result) {
props.onSubmit(state.result)
}
}, [props, state.result])
const addOsasuoritus = useCallback(() => {
state.result && onAdd(state.result)
}, [onAdd, state.result])

return (
<Modal>
<ModalTitle>{t('Oppiaineen lisäys')}</ModalTitle>
<ModalTitle>{t('Lisää osasuoritus')}</ModalTitle>
<ModalBody>
{tunnisteet && (
<label>
{t('Oppiaine')}
<DialogSelect
options={tunnisteet}
value={state.tunniste.value && koodiviiteId(state.tunniste.value)}
onChange={onTunniste}
testId="tunniste"
/>
</label>
)}
{state.kieli.visible && kielet && (
<label>
{t('Kieli')}
<DialogSelect
options={kielet}
value={state.kieli.value && koodiviiteId(state.kieli.value)}
onChange={(o) => state.kieli.set(o?.value)}
testId="kieli"
/>
</label>
)}
{state.ryhmä.visible && ryhmät && (
<label>
{t('Aineryhmä')}
<DialogSelect
options={ryhmät}
value={state.ryhmä.value && koodiviiteId(state.ryhmä.value)}
onChange={(o) => state.ryhmä.set(o?.value)}
testId="ryhmä"
/>
</label>
)}
{state.matematiikanOppimäärä.visible && matematiikanOppimäärät && (
{state.lukioTunniste.visible && lukioTunnisteet && (
<label>
{t('Oppimäärä')}
{t('Osasuoritus')}
<DialogSelect
options={matematiikanOppimäärät}
options={lukioTunnisteet}
value={
state.matematiikanOppimäärä.value &&
koodiviiteId(state.matematiikanOppimäärä.value)
state.lukioTunniste.value &&
koodiviiteId(state.lukioTunniste.value)
}
onChange={(o) => state.matematiikanOppimäärä.set(o?.value)}
testId="matematiikanOppimäärä"
onChange={(o) => state.lukioTunniste.set(o?.value)}
testId="tunniste"
/>
</label>
)}
{state.äidinkielenKieli.visible && äidinkielenKielet && (
{state.paikallinenTunniste.visible && (
<PaikallinenKoulutusFields onChange={onPaikallinenKoulutus} />
)}
{state.lukiokurssinTyyppi.visible && kurssityypit && (
<label>
{t('Kieli')}
{t('Kurssin tyyppi')}
<DialogSelect
options={äidinkielenKielet}
options={kurssityypit}
value={
state.äidinkielenKieli.value &&
koodiviiteId(state.äidinkielenKieli.value)
state.lukiokurssinTyyppi.value &&
koodiviiteId(state.lukiokurssinTyyppi.value)
}
onChange={(o) => state.äidinkielenKieli.set(o?.value)}
testId="äidinkielenKieli"
onChange={(o) => state.lukiokurssinTyyppi.set(o?.value)}
testId="tunniste"
/>
</label>
)}
{state.paikallinenTunniste.visible && (
<PaikallinenKoulutusFields onChange={onPaikallinenKoulutus} />
)}
</ModalBody>
<ModalFooter>
<FlatButton onClick={props.onClose} testId="cancel">
{t('Peruuta')}
</FlatButton>
<RaisedButton
onClick={onSubmit}
disabled={!state.result}
testId="submit"
>
{t('Lisää opiskeluoikeus')}
<FlatButton onClick={props.onClose}>{t('Peruuta')}</FlatButton>
<RaisedButton onClick={addOsasuoritus} disabled={!state.result}>
{t('Lisää')}
</RaisedButton>
</ModalFooter>
</Modal>
Expand Down
Loading

0 comments on commit 20b893a

Please sign in to comment.