src/stores/OpetussuunnitelmaDataStore.ts
import _ from 'lodash';
import { Getter, State, Store } from '@shared/stores/store';
import { Location } from 'vue-router';
import mime from 'mime-types';
import { YlopsNavigationNodeDto,
baseURL,
Dokumentit,
DokumentitParams,
Liitetiedostot,
LiitetiedostotParam,
Opetussuunnitelmat,
Termisto,
OpetussuunnitelmatJulkiset,
OpetussuunnitelmaExportDto,
DokumenttiDtoTilaEnum,
} from '@shared/api/ylops';
import { Kielet } from '@shared/stores/kieli';
import {
baseURL as perusteBaseURL,
Liitetiedostot as PerusteLiitetiedostot,
LiitetiedostotParam as PerusteLiitetiedostotParam,
Perusteet,
PerusteKaikkiDto,
Termit,
Julkaisut,
} from '@shared/api/eperusteet';
import {
buildNavigation,
buildTiedot,
filterNavigation,
NavigationFilter,
NavigationNode,
} from '@shared/utils/NavigationBuilder';
import { IOpetussuunnitelmaStore } from './IOpetussuunitelmaStore';
import { deepFind } from '@shared/utils/helpers';
const PaikallisetKielet = new Set(['VK', 'EN', 'LA', 'RA', 'SM', 'SA', 'VE', 'IA', 'EA', 'PO', 'KI', 'JP', 'AR', 'KX']);
interface NavigationQueryResult { parent: YlopsNavigationNodeDto | null, target: YlopsNavigationNodeDto };
@Store
export class OpetussuunnitelmaDataStore implements IOpetussuunnitelmaStore {
@State() public opetussuunnitelma: OpetussuunnitelmaExportDto | null = null;
@State() public opetussuunnitelmaPerusteenId: number | null = null;
@State() public opetussuunnitelmaId: number;
@State() public esikatselu: boolean | undefined = undefined;
@State() public revision: number | undefined = undefined;
@State() public navigation: YlopsNavigationNodeDto | null = null;
@State() public dokumentit: any = {};
@State() public currentRoute: Location | null = null;
@State() public sidenavFilter: NavigationFilter = {
label: '',
isEnabled: false,
};
@State() public perusteTermit: object[] | null = null;
@State() public perusteKuvat: object[] | null = null;
@State() public termit: object[] | null = null;
@State() public kuvat: object[] | null = null;
@State() public perusteKaikki: PerusteKaikkiDto | null = null;
public static async create(opetussuunnitelmaId: number, revision: number | undefined = undefined) {
const result = new OpetussuunnitelmaDataStore(opetussuunnitelmaId, revision);
await result.init();
return result;
}
constructor(opetussuunnitelmaId: number, revision) {
this.opetussuunnitelmaId = opetussuunnitelmaId;
this.esikatselu = revision === '0' ? true : undefined;
this.revision = revision;
}
async init() {
await Promise.all([this.fetchOpetussuunnitelma(), this.fetchNavigation()]);
if (this.opetussuunnitelmaPerusteenId) {
this.fetchPerusteTermit(this.opetussuunnitelmaPerusteenId);
this.fetchPerusteKuvat(this.opetussuunnitelmaPerusteenId);
}
this.fetchTermit();
this.fetchKuvat();
if (this.opetussuunnitelma?.peruste) {
const perusteenJulkaisut = (await Julkaisut.getKaikkiJulkaisut(this.opetussuunnitelma.peruste.id!)).data;
const rev = _.chain(perusteenJulkaisut)
.filter(julkaisu => julkaisu.luotu! >= this.opetussuunnitelma!.peruste!.globalVersion?.aikaleima!)
.sortBy('luotu')
.first()
.get('revision')
.value();
this.perusteKaikki = (await Perusteet.getKokoSisalto(this.opetussuunnitelma.peruste.id!, rev)).data;
}
}
async fetchOpetussuunnitelma() {
this.opetussuunnitelma = null;
this.opetussuunnitelmaPerusteenId = null;
this.opetussuunnitelma = (await OpetussuunnitelmatJulkiset.getOpetussuunnitelmaJulkaistu(this.opetussuunnitelmaId, this.esikatselu)).data;
this.opetussuunnitelmaPerusteenId = this.opetussuunnitelma.perusteenId ? this.opetussuunnitelma.perusteenId : null;
}
public getJulkaistuSisalto(filter) {
return deepFind(filter, this.opetussuunnitelma);
}
public getJulkaistuPerusteSisalto(filter) {
return deepFind(filter, this.perusteKaikki);
}
async fetchPerusteTermit(perusteenId: number) {
this.perusteTermit = null;
this.perusteTermit = (await Termit.getAllTermit(perusteenId)).data;
}
async fetchPerusteKuvat(perusteenId: number) {
this.perusteKuvat = null;
this.perusteKuvat = _.map((await PerusteLiitetiedostot.getAllKuvat(perusteenId)).data, kuva => ({
id: kuva.id!,
kuva,
src: perusteBaseURL + PerusteLiitetiedostotParam.getKuva(perusteenId, this.getKuvaFilename(kuva)).url,
}));
}
private getKuvaFilename(liite) {
return liite.id! + '.' + mime.extension(liite.mime);
}
async fetchTermit() {
this.termit = null;
this.termit = (await Termisto.getAllTermit(this.opetussuunnitelmaId)).data;
}
async fetchKuvat() {
this.kuvat = null;
this.kuvat = _.map((await Liitetiedostot.getAllLiitteet(this.opetussuunnitelmaId)).data, kuva => ({
id: kuva.id!,
kuva,
src: baseURL + LiitetiedostotParam.getLiitetiedosto(this.opetussuunnitelmaId, this.getLiiteFilename(kuva)).url,
}));
}
private getLiiteFilename(liite) {
return liite.id! + '.' + mime.extension(liite.tyyppi);
}
findBy(navi: YlopsNavigationNodeDto, fn: (value: YlopsNavigationNodeDto) => boolean, parent: YlopsNavigationNodeDto | null = null): NavigationQueryResult[] {
const kohde = _.get(navi, 'meta.koodi');
const result: NavigationQueryResult[] = [];
if (fn(navi)) {
result.push({
parent,
target: navi,
});
}
for (const ch of (navi.children || [])) {
const nodes = this.findBy(ch, fn, navi);
if (nodes) {
result.push(...nodes);
}
}
return result;
}
findByKoodi(navi: YlopsNavigationNodeDto, koodi: string) {
return this.findBy(navi, (node) => {
const kohde = _.toString(_.get(node, 'meta.koodi'));
return (kohde === koodi || _.get(kohde, 'arvo') === koodi);
});
}
findByTyyppi(navi: YlopsNavigationNodeDto, tyyppi: string) {
return this.findBy(navi, (node) => node.type === tyyppi);
}
movePaikallisetOppiaineet(navi: YlopsNavigationNodeDto) {
const vieraatKielet = this.findByKoodi(navi, 'VK');
if (!_.isEmpty(vieraatKielet)) {
const paikallisetOppiaineet = this.findByTyyppi(navi, 'poppiaine');
const paikallisetKielet = _(paikallisetOppiaineet)
.filter((node: any) => {
const start = (_.get(node, 'target.meta.koodi') || '').substr(0, 2);
return PaikallisetKielet.has(start);
})
.value();
let vk = vieraatKielet[0].target; {
const op = this.findByTyyppi(vk, 'oppimaarat');
if (!_.isEmpty(op)) {
vk = _.first(op)!.target;
}
}
const paikalliset: YlopsNavigationNodeDto[] = [];
for (const paikallinen of paikallisetKielet) {
_.remove(paikallinen.parent!.children || [], { id: paikallinen.target.id });
paikalliset.push(paikallinen.target);
}
vk.children = [...(vk.children || []), ..._.sortBy(paikalliset, 'meta.koodi')];
}
}
async fetchNavigation() {
this.navigation = null;
const navigation = (await Opetussuunnitelmat.getNavigationPublic(this.opetussuunnitelmaId, Kielet.getSisaltoKieli.value, this.esikatselu)).data;
this.movePaikallisetOppiaineet(navigation);
this.navigation = navigation;
}
@Getter(state => state.opetussuunnitelma.tila)
public readonly tila!: string;
@Getter(state => [...(state.termit || []), ...(state.perusteTermit || [])])
public readonly kaikkiTermit!: any[];
@Getter(state => state.opetussuunnitelma.koulutustyyppi)
public readonly koulutustyyppi!: string;
@Getter(state => {
return !state.opetussuunnitelma || !state.navigation;
})
public readonly sidenavLoading!: boolean;
@Getter(state => {
if (!state.opetussuunnitelma || !state.navigation) {
return null;
}
else {
const tiedot = buildTiedot('opetussuunnitelmaTiedot', {
opetussuunnitelmaId: _.toString(state.opetussuunnitelmaId),
...(state.revision && { revision: state.revision }),
});
return buildNavigation(state.navigation, tiedot, true, state.revision);
}
})
public readonly sidenav!: NavigationNode | null;
@Getter((state, getters) => {
if (!getters.sidenav) {
return null;
}
const pathKeys = _.map(_.get(getters, 'current.path'), 'key');
const onPath = node => {
const parent = node.path[_.size(node.path) - 2];
return _.includes(pathKeys, node.key)
|| (parent && _.includes(pathKeys, parent.key));
};
const map = (value, depth = 0) => {
return {
...value,
isVisible: !getters.current || depth === 1 || onPath(value),
children: _.map(value.children, child => map(child, depth + 1)),
};
};
return map(getters.sidenav);
})
public readonly collapsedSidenav!: NavigationNode | null;
@Getter((state, getters) => {
if (state.sidenavFilter.isEnabled) {
return filterNavigation(getters.sidenav, state.sidenavFilter);
}
else {
return getters.collapsedSidenav;
}
})
public readonly filteredSidenav!: NavigationNode | null;
@Getter((state, getters) => {
const root = getters.sidenav;
const result: Array<NavigationNode> = [];
function traverseTree(node: NavigationNode) {
result.push(node);
(node.children || [])
.map(child => {
traverseTree(child);
return child;
});
}
if (root) {
traverseTree(root);
}
return result;
})
public readonly flattenedSidenav!: NavigationNode[];
@Getter((state, getters) => {
if (!getters.flattenedSidenav) {
return {};
}
const koodit = _.chain(getters.flattenedSidenav)
.filter('meta.koodi.uri')
.keyBy('meta.koodi.uri')
.value();
const rawKoodit = _.chain(getters.flattenedSidenav)
.filter('meta.koodi')
.filter(node => _.isString(node.meta.koodi))
.keyBy('meta.koodi')
.value();
return _.assign(koodit, rawKoodit);
})
public readonly navigationByUri!: { [uri: string]: NavigationNode };
@Getter((state, getters) => {
if (!getters.flattenedSidenav) {
return {};
}
const koodit = _.chain(getters.flattenedSidenav)
.filter(node => node.type === 'oppiaine' || node.type === 'poppiaine')
.filter('meta.koodi.uri')
.keyBy('meta.koodi.uri')
.value();
const rawKoodit = _.chain(getters.flattenedSidenav)
.filter(node => node.type === 'oppiaine' || node.type === 'poppiaine')
.filter('meta.koodi')
.filter(node => _.isString(node.meta.koodi))
.keyBy('meta.koodi')
.value();
return _.assign(koodit, rawKoodit);
})
public readonly oppiaineetNavigationByUri!: { [uri: string]: NavigationNode };
@Getter((state, getters) => {
if (getters.flattenedSidenav && state.currentRoute) {
for (const node of getters.flattenedSidenav) {
if (node.location && _.isMatch(state.currentRoute, node.location)) {
return node || null;
}
}
}
return null;
})
public readonly current!: NavigationNode | null;
public async getDokumentit() {
if (!this.opetussuunnitelma) {
return;
}
const sisaltoKieli = Kielet.getSisaltoKieli.value;
if (this.esikatselu) {
const dokumenttiId = (await Dokumentit.getLatestDokumenttiId(this.opetussuunnitelmaId, sisaltoKieli)).data;
this.asetaKielenDokumentti(dokumenttiId);
}
else {
const julkaistuDokumentti = (await Dokumentit.getJulkaistuDokumentti(this.opetussuunnitelmaId, sisaltoKieli)).data;
if (julkaistuDokumentti?.tila === _.toLower(DokumenttiDtoTilaEnum.VALMIS)) {
this.asetaKielenDokumentti(julkaistuDokumentti.id);
}
}
}
private asetaKielenDokumentti(dokumenttiId) {
if (dokumenttiId) {
this.dokumentit[Kielet.getSisaltoKieli.value] = baseURL + DokumentitParams.get(_.toString(dokumenttiId)).url;
}
}
public updateRoute(route) {
this.currentRoute = route;
}
public readonly updateFilter = _.debounce((filter: NavigationFilter) => {
this.sidenavFilter = filter;
}, 300);
}