Merge branch 'main' into feat/abscense-registration-hjarntorget
This commit is contained in:
commit
957650699c
104
CHANGELOG.md
104
CHANGELOG.md
|
@ -1,3 +1,107 @@
|
|||
## [2.10.2](https://github.com/kolplattformen/skolplattformen/compare/v2.10.1...v2.10.2) (2021-12-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 adjust fakeData lessons offset in ht ([#598](https://github.com/kolplattformen/skolplattformen/issues/598)) ([3f69bc8](https://github.com/kolplattformen/skolplattformen/commit/3f69bc89aaa7eb1cf4ade789551667b960ff8825))
|
||||
|
||||
## [2.10.1](https://github.com/kolplattformen/skolplattformen/compare/v2.10.0...v2.10.1) (2021-12-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 scroll in timetable ([#597](https://github.com/kolplattformen/skolplattformen/issues/597)) ([f844a3c](https://github.com/kolplattformen/skolplattformen/commit/f844a3cdd4ea26b6a4b76e4236debec7e6e83986))
|
||||
|
||||
# [2.10.0](https://github.com/kolplattformen/skolplattformen/compare/v2.9.1...v2.10.0) (2021-12-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Ämnesnamn syns nu i schemat i Hjärntorget. ([#596](https://github.com/kolplattformen/skolplattformen/issues/596)) ([14ff985](https://github.com/kolplattformen/skolplattformen/commit/14ff985b0c7a0c9ab9c8547679caff66c7b5aa1f))
|
||||
|
||||
## [2.9.1](https://github.com/kolplattformen/skolplattformen/compare/v2.9.0...v2.9.1) (2021-12-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Felaktig sortering av lektioner ([#595](https://github.com/kolplattformen/skolplattformen/issues/595)) ([ed3a27b](https://github.com/kolplattformen/skolplattformen/commit/ed3a27bba185b39fd8581b639ac7efc03b050d6e)), closes [#591](https://github.com/kolplattformen/skolplattformen/issues/591)
|
||||
|
||||
# [2.9.0](https://github.com/kolplattformen/skolplattformen/compare/v2.8.0...v2.9.0) (2021-12-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Hämta lärare och skolkontakter från api-skolplattfomen och visa lärarens namn i schemat ([#589](https://github.com/kolplattformen/skolplattformen/issues/589)) ([b7dbd35](https://github.com/kolplattformen/skolplattformen/commit/b7dbd356c652bf53a9d73dd38f11744ff364470b))
|
||||
|
||||
# [2.8.0](https://github.com/kolplattformen/skolplattformen/compare/v2.7.3...v2.8.0) (2021-12-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Ingen text syns i dark mode när inga barn hittas ([bce1165](https://github.com/kolplattformen/skolplattformen/commit/bce1165f300749502351fe28ee8f0c5f3ce7ee3c)), closes [#571](https://github.com/kolplattformen/skolplattformen/issues/571)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 bumped to 3.0.2 for new version releasea ([2af189e](https://github.com/kolplattformen/skolplattformen/commit/2af189ef0fb23723dae982382bee169e2c7ed8f6))
|
||||
|
||||
## [2.7.3](https://github.com/kolplattformen/skolplattformen/compare/v2.7.2...v2.7.3) (2021-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Store childs personalIdNumbers in settings ([cc3fd86](https://github.com/kolplattformen/skolplattformen/commit/cc3fd8670c37be2b5f3e9f642bb3b1882350e2f6))
|
||||
|
||||
## [2.7.2](https://github.com/kolplattformen/skolplattformen/compare/v2.7.1...v2.7.2) (2021-12-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Add missing translations for calendar ([7ada994](https://github.com/kolplattformen/skolplattformen/commit/7ada9945dfc7dd5766cd7a3208d62cf4c1a2659f))
|
||||
|
||||
## [2.7.1](https://github.com/kolplattformen/skolplattformen/compare/v2.7.0...v2.7.1) (2021-12-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Add translation to week ([cfa39de](https://github.com/kolplattformen/skolplattformen/commit/cfa39de3934e2386d90f37ad2c3dc830106e175a))
|
||||
|
||||
# [2.7.0](https://github.com/kolplattformen/skolplattformen/compare/v2.6.0...v2.7.0) (2021-12-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Add week number and calendar dates to timetable ([6fbbcc8](https://github.com/kolplattformen/skolplattformen/commit/6fbbcc803e92e288904be1ffba5e380bd9523100))
|
||||
|
||||
# [2.6.0](https://github.com/kolplattformen/skolplattformen/compare/v2.5.1...v2.6.0) (2021-12-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Frontpage date tweaks ([#582](https://github.com/kolplattformen/skolplattformen/issues/582)) ([66e7811](https://github.com/kolplattformen/skolplattformen/commit/66e7811b83e96f9fb83aa82cb34736f38a3bf16a))
|
||||
|
||||
## [2.5.1](https://github.com/kolplattformen/skolplattformen/compare/v2.5.0...v2.5.1) (2021-12-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Show the weekday on startpage if not today ([df28066](https://github.com/kolplattformen/skolplattformen/commit/df2806648ab6b573d277a338f76fb199cdd307a2))
|
||||
|
||||
# [2.5.0](https://github.com/kolplattformen/skolplattformen/compare/v2.4.0...v2.5.0) (2021-12-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Skip to the next day in calendar ([#425](https://github.com/kolplattformen/skolplattformen/issues/425)) ([fce1d98](https://github.com/kolplattformen/skolplattformen/commit/fce1d98847f4cc7c27bfa359b1d2b1bdc86e12ea))
|
||||
|
||||
# [2.4.0](https://github.com/kolplattformen/skolplattformen/compare/v2.3.2...v2.4.0) (2021-12-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Clear personal cache on login and logout ([#572](https://github.com/kolplattformen/skolplattformen/issues/572)) ([bf29ab5](https://github.com/kolplattformen/skolplattformen/commit/bf29ab58edd13db62b34f873a3429d319c0e7297))
|
||||
* 🎸 Fix image load and typescript errors ([#570](https://github.com/kolplattformen/skolplattformen/issues/570)) ([933a884](https://github.com/kolplattformen/skolplattformen/commit/933a8840a3ebd049711a000ca6faf3e534f77ace))
|
||||
|
||||
## [2.3.2](https://github.com/kolplattformen/skolplattformen/compare/v2.3.1...v2.3.2) (2021-12-01)
|
||||
|
||||
|
||||
|
|
|
@ -14,9 +14,13 @@ const path = require('path')
|
|||
const fs = require('fs')
|
||||
const HttpProxyAgent = require('https-proxy-agent')
|
||||
const agentWrapper = require('./app/agentFetchWrapper')
|
||||
const init = require('@skolplattformen/api-skolplattformen').default
|
||||
const initSkolplattformen = require('@skolplattformen/api-skolplattformen').default
|
||||
const initHjarntorget = require('@skolplattformen/api-hjarntorget').default
|
||||
|
||||
const [, , personalNumber, platform] = process.argv
|
||||
const isHjarntorget = platform && platform.startsWith('hj')
|
||||
const init = isHjarntorget ? initHjarntorget : initSkolplattformen;
|
||||
|
||||
const [, , personalNumber] = process.argv
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
const cookieJar = new CookieJar()
|
||||
let bankIdUsed = false
|
||||
|
@ -136,10 +140,9 @@ async function Login(api) {
|
|||
try {
|
||||
console.log('Attempt to use saved session cookie to login')
|
||||
const rawContent = await readFile(`${recordFolder}/latestSessionCookie.txt`)
|
||||
const sessionCookie = JSON.parse(rawContent)
|
||||
|
||||
await api.setSessionCookie(`${sessionCookie.key}=${sessionCookie.value}`)
|
||||
|
||||
const sessionCookies = JSON.parse(rawContent)
|
||||
await api.setSessionCookie(`${sessionCookies[0].key}=${sessionCookies[0].value}`)
|
||||
|
||||
useBankId = false
|
||||
console.log('Login with old cookie succeeded')
|
||||
} catch (error) {
|
||||
|
@ -177,10 +180,12 @@ function ensureDirectoryExistence(filePath) {
|
|||
fs.mkdirSync(dirname)
|
||||
}
|
||||
|
||||
|
||||
function getSessionCookieFromCookieJar() {
|
||||
const cookies = cookieJar.getCookiesSync('https://etjanst.stockholm.se')
|
||||
const sessionCookie = cookies.find((c) => c.key === 'SMSESSION')
|
||||
return sessionCookie
|
||||
const cookieUrl = isHjarntorget ? 'https://hjarntorget.goteborg.se' : 'https://etjanst.stockholm.se'
|
||||
const cookies = cookieJar.getCookiesSync(cookieUrl)
|
||||
const sessionCookieKey = isHjarntorget ? 'JSESSIONID' : 'SMSESSION'
|
||||
return cookies.find(c => c.key === sessionCookieKey)
|
||||
}
|
||||
|
||||
const record = async (info, data) => {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
"rules": {"no-console":"warn"}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
|
|
|
@ -19,13 +19,16 @@ import { translations } from './utils/translation'
|
|||
const reporter: Reporter | undefined = __DEV__
|
||||
? {
|
||||
log: (message: string) => console.log(message),
|
||||
error: (error: Error, label?: string) => console.error(label, error),
|
||||
error: (error: Error, label?: string) => console.log(label, error),
|
||||
}
|
||||
: undefined
|
||||
|
||||
if (__DEV__) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const DevMenu = require('react-native-dev-menu')
|
||||
DevMenu.addItem('Clear AsyncStorage from all contents', () =>
|
||||
AsyncStorage.clear().then(() => logAsyncStorage())
|
||||
)
|
||||
DevMenu.addItem('Log AsyncStorage contents', () => logAsyncStorage())
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ android {
|
|||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 20000
|
||||
versionName "3.0.1"
|
||||
versionName "3.0.3"
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
|
|
|
@ -18,6 +18,7 @@ import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
|
|||
import * as Yup from 'yup'
|
||||
import { defaultStackStyling } from '../design/navigationThemes'
|
||||
import usePersonalStorage from '../hooks/usePersonalStorage'
|
||||
import useSettingsStorage from '../hooks/useSettingsStorage'
|
||||
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
|
||||
import { studentName } from '../utils/peopleHelpers'
|
||||
import { useSMS } from '../utils/SMS'
|
||||
|
@ -70,12 +71,11 @@ const Absence = () => {
|
|||
const route = useRoute<AbsenceRouteProps>()
|
||||
const { sendSMS } = useSMS()
|
||||
const { child } = route.params
|
||||
const [personalIdFromStorage, setPersonalIdInStorage] = usePersonalStorage(
|
||||
user,
|
||||
`@childssn.${child.id}`,
|
||||
''
|
||||
)
|
||||
const [personalIdentityNumber, setPersonalIdentityNumber] = React.useState('')
|
||||
const [personalIdsFromStorage, setPersonalIdInStorage] = useSettingsStorage(
|
||||
'childPersonalIdentityNumber'
|
||||
)
|
||||
const personalIdKey = `@childPersonalIdNumber.${child.id}`
|
||||
const minumumDate = moment().hours(8).minute(0)
|
||||
const maximumDate = moment().hours(17).minute(0)
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
|
@ -96,15 +96,19 @@ const Absence = () => {
|
|||
)
|
||||
}
|
||||
|
||||
setPersonalIdInStorage(values.personalIdentityNumber)
|
||||
setPersonalIdentityNumber(values.personalIdentityNumber)
|
||||
const toStore = {
|
||||
...personalIdsFromStorage,
|
||||
...{ [personalIdKey]: personalIdNumber },
|
||||
}
|
||||
setPersonalIdInStorage(toStore)
|
||||
},
|
||||
[sendSMS, setPersonalIdInStorage]
|
||||
[personalIdKey, personalIdsFromStorage, sendSMS, setPersonalIdInStorage]
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
const personalIdFromStorage = personalIdsFromStorage[personalIdKey] || ''
|
||||
setPersonalIdentityNumber(personalIdFromStorage || '')
|
||||
}, [child, personalIdFromStorage, user])
|
||||
}, [child, personalIdKey, personalIdsFromStorage, user])
|
||||
|
||||
const initialValues: AbsenceFormValues = {
|
||||
displayStartTimePicker: false,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { CalendarItem } from '@skolplattformen/api-skolplattformen'
|
||||
import { useCalendar } from '@skolplattformen/hooks'
|
||||
import { CalendarItem } from '@skolplattformen/api'
|
||||
import {
|
||||
Divider,
|
||||
List,
|
||||
|
@ -10,8 +10,9 @@ import {
|
|||
} from '@ui-kitten/components'
|
||||
import moment from 'moment'
|
||||
import React from 'react'
|
||||
import { ListRenderItemInfo, View } from 'react-native'
|
||||
import { Typography } from '../styles'
|
||||
import { ListRenderItemInfo, RefreshControl, View } from 'react-native'
|
||||
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
|
||||
import { translate } from '../utils/translation'
|
||||
import { useChild } from './childContext.component'
|
||||
import { CalendarOutlineIcon } from './icon.component'
|
||||
import { SaveToCalendar } from './saveToCalendar.component'
|
||||
|
@ -19,7 +20,7 @@ import { Week } from './week.component'
|
|||
|
||||
export const Calendar = () => {
|
||||
const child = useChild()
|
||||
const { data } = useCalendar(child)
|
||||
const { data, status, reload } = useCalendar(child)
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
|
||||
const formatStartDate = (startDate: moment.MomentInput) => {
|
||||
|
@ -28,37 +29,55 @@ export const Calendar = () => {
|
|||
'll'
|
||||
)} • ${date.fromNow()}`
|
||||
|
||||
// Hack to remove yarn if it is this year
|
||||
// Hack to remove year if it is this year
|
||||
const currentYear = moment().year().toString(10)
|
||||
return output.replace(currentYear, '')
|
||||
}
|
||||
|
||||
const sortedData = () => {
|
||||
if (!data) return []
|
||||
|
||||
return data.sort((a, b) =>
|
||||
a.startDate && b.startDate ? a.startDate.localeCompare(b.startDate) : 0
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Week child={child} />
|
||||
{data && data.length > 0 && (
|
||||
<List
|
||||
data={data.sort((a, b) =>
|
||||
a.startDate && b.startDate
|
||||
? a.startDate.localeCompare(b.startDate)
|
||||
: 0
|
||||
)}
|
||||
ItemSeparatorComponent={Divider}
|
||||
renderItem={({ item }: ListRenderItemInfo<CalendarItem>) => (
|
||||
<ListItem
|
||||
disabled={true}
|
||||
title={`${item.title}`}
|
||||
description={(props) => (
|
||||
<Text style={[props?.style, styles.description]}>
|
||||
{formatStartDate(item.startDate)}
|
||||
</Text>
|
||||
)}
|
||||
accessoryLeft={CalendarOutlineIcon}
|
||||
accessoryRight={() => <SaveToCalendar event={item} />}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<List
|
||||
data={sortedData()}
|
||||
ItemSeparatorComponent={Divider}
|
||||
ListEmptyComponent={
|
||||
<View style={styles.emptyState}>
|
||||
<Text style={styles.emptyStateHeadline} category="h6">
|
||||
{translate('calender.emptyHeadline')}
|
||||
</Text>
|
||||
<Text style={styles.emptyStateDescription}>
|
||||
{translate('calender.emptyText')}
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
renderItem={({ item }: ListRenderItemInfo<CalendarItem>) => (
|
||||
<ListItem
|
||||
disabled={true}
|
||||
title={`${item.title}`}
|
||||
description={(props) => (
|
||||
<Text style={[props?.style, styles.description]}>
|
||||
{formatStartDate(item.startDate)}
|
||||
</Text>
|
||||
)}
|
||||
accessoryLeft={CalendarOutlineIcon}
|
||||
accessoryRight={() => <SaveToCalendar event={item} />}
|
||||
/>
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={status === 'loading'}
|
||||
onRefresh={reload}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
@ -73,4 +92,18 @@ const themedStyles = StyleService.create({
|
|||
...Typography.fontSize.xs,
|
||||
color: 'text-hint-color',
|
||||
},
|
||||
emptyState: {
|
||||
...LayoutStyle.center,
|
||||
...LayoutStyle.flex.full,
|
||||
},
|
||||
emptyStateHeadline: {
|
||||
...Typography.align.center,
|
||||
margin: Sizing.t4,
|
||||
},
|
||||
emptyStateDescription: {
|
||||
...Typography.align.center,
|
||||
lineHeight: 21,
|
||||
paddingHorizontal: Sizing.t3,
|
||||
margin: Sizing.t4,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Child } from '@skolplattformen/api-skolplattformen'
|
||||
import { Child } from '@skolplattformen/api'
|
||||
import React, { createContext, useContext } from 'react'
|
||||
|
||||
interface ChildProviderProps {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable react-native-a11y/has-accessibility-hint */
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { Child } from '@skolplattformen/api-skolplattformen'
|
||||
import { Child } from '@skolplattformen/api'
|
||||
import {
|
||||
useCalendar,
|
||||
useClassmates,
|
||||
|
@ -16,11 +16,12 @@ import {
|
|||
Text,
|
||||
useStyleSheet,
|
||||
} from '@ui-kitten/components'
|
||||
import moment from 'moment'
|
||||
import React from 'react'
|
||||
import moment, { Moment } from 'moment'
|
||||
import React, { useEffect } from 'react'
|
||||
import { TouchableOpacity, useColorScheme, View } from 'react-native'
|
||||
import { useTranslation } from '../hooks/useTranslation'
|
||||
import { Colors, Layout, Sizing } from '../styles'
|
||||
import { getMeaningfulStartingDate } from '../utils/calendarHelpers'
|
||||
import { studentName } from '../utils/peopleHelpers'
|
||||
import { DaySummary } from './daySummary.component'
|
||||
import { AlertIcon, RightArrowIcon } from './icon.component'
|
||||
|
@ -30,13 +31,20 @@ import { StudentAvatar } from './studentAvatar.component'
|
|||
interface ChildListItemProps {
|
||||
child: Child
|
||||
color: string
|
||||
updated: string
|
||||
currentDate?: Moment
|
||||
}
|
||||
type ChildListItemNavigationProp = StackNavigationProp<
|
||||
RootStackParamList,
|
||||
'Children'
|
||||
>
|
||||
|
||||
export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
||||
export const ChildListItem = ({
|
||||
child,
|
||||
color,
|
||||
updated,
|
||||
currentDate = moment(),
|
||||
}: ChildListItemProps) => {
|
||||
// Forces rerender when child.id changes
|
||||
React.useEffect(() => {
|
||||
// noop
|
||||
|
@ -44,17 +52,36 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
|
||||
const navigation = useNavigation<ChildListItemNavigationProp>()
|
||||
const { t } = useTranslation()
|
||||
const { data: notifications } = useNotifications(child)
|
||||
const { data: news } = useNews(child)
|
||||
const { data: classmates } = useClassmates(child)
|
||||
const { data: calendar } = useCalendar(child)
|
||||
const { data: menu } = useMenu(child)
|
||||
const { data: schedule } = useSchedule(
|
||||
const { data: notifications, reload: notificationsReload } =
|
||||
useNotifications(child)
|
||||
const { data: news, status: newsStatus, reload: newsReload } = useNews(child)
|
||||
const { data: classmates, reload: classmatesReload } = useClassmates(child)
|
||||
const { data: calendar, reload: calendarReload } = useCalendar(child)
|
||||
const { data: menu, reload: menuReload } = useMenu(child)
|
||||
const { data: schedule, reload: scheduleReload } = useSchedule(
|
||||
child,
|
||||
moment().toISOString(),
|
||||
moment().add(7, 'days').toISOString()
|
||||
moment(currentDate).toISOString(),
|
||||
moment(currentDate).add(7, 'days').toISOString()
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
// Do not refresh if updated is empty (first render of component)
|
||||
if (updated === '') return
|
||||
|
||||
newsReload()
|
||||
classmatesReload()
|
||||
notificationsReload()
|
||||
calendarReload()
|
||||
menuReload()
|
||||
scheduleReload()
|
||||
|
||||
// Without eslint-disable below we get into a forever loop
|
||||
// because the function pointers to reload functions change on every reload.
|
||||
// I do not know a workaround for this.
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [updated])
|
||||
|
||||
const notificationsThisWeek = notifications.filter(
|
||||
({ dateCreated, dateModified }) => {
|
||||
const date = dateModified || dateCreated
|
||||
|
@ -63,8 +90,8 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
)
|
||||
|
||||
const newsThisWeek = news.filter(({ modified, published }) => {
|
||||
const date = modified || published
|
||||
return date ? moment(date).isSame(moment(), 'week') : false
|
||||
const newsDate = modified || published
|
||||
return newsDate ? moment(newsDate).isSame(currentDate, 'week') : false
|
||||
})
|
||||
|
||||
const scheduleAndCalendarThisWeek = [
|
||||
|
@ -73,14 +100,14 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
].filter(({ startDate }) =>
|
||||
startDate
|
||||
? moment(startDate).isBetween(
|
||||
moment().startOf('day'),
|
||||
moment().add(7, 'days')
|
||||
moment(currentDate).startOf('day'),
|
||||
moment(currentDate).add(7, 'days')
|
||||
)
|
||||
: false
|
||||
)
|
||||
|
||||
const displayDate = (date: moment.MomentInput) => {
|
||||
return moment(date).fromNow()
|
||||
const displayDate = (inputDate: moment.MomentInput) => {
|
||||
return moment(inputDate).fromNow()
|
||||
}
|
||||
|
||||
const getClassName = () => {
|
||||
|
@ -118,6 +145,16 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
const className = getClassName()
|
||||
const styles = useStyleSheet(themeStyles)
|
||||
const isDarkMode = useColorScheme() === 'dark'
|
||||
const meaningfulStartingDate = getMeaningfulStartingDate(currentDate)
|
||||
|
||||
// Hide menu if we want to show monday but it is not monday yet.
|
||||
// The menu for next week is not available until monday
|
||||
const shouldShowLunchMenu =
|
||||
menu[meaningfulStartingDate.isoWeekday() - 1] &&
|
||||
!(
|
||||
meaningfulStartingDate.isoWeekday() === 1 &&
|
||||
currentDate.isoWeekday() !== 1
|
||||
)
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
|
@ -142,12 +179,15 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
/>
|
||||
</View>
|
||||
</View>
|
||||
<DaySummary child={child} />
|
||||
|
||||
<DaySummary child={child} date={meaningfulStartingDate} />
|
||||
|
||||
{scheduleAndCalendarThisWeek.slice(0, 3).map((calendarItem, i) => (
|
||||
<Text category="p1" key={i}>
|
||||
{`${calendarItem.title} (${displayDate(calendarItem.startDate)})`}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
<Text category="c2" style={styles.label}>
|
||||
{t('navigation.news')}
|
||||
</Text>
|
||||
|
@ -156,11 +196,13 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
{notification.message}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
{newsThisWeek.slice(0, 3).map((newsItem, i) => (
|
||||
<Text category="p1" key={i}>
|
||||
{newsItem.header ?? ''}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
{scheduleAndCalendarThisWeek.length ||
|
||||
notificationsThisWeek.length ||
|
||||
newsThisWeek.length ? null : (
|
||||
|
@ -168,16 +210,20 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
|
|||
{t('news.noNewNewsItemsThisWeek')}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{!menu[moment().isoWeekday() - 1] ? null : (
|
||||
{shouldShowLunchMenu ? (
|
||||
<>
|
||||
<Text category="c2" style={styles.label}>
|
||||
{t('schedule.lunch')}
|
||||
{meaningfulStartingDate.format(
|
||||
'[' + t('schedule.lunch') + '] dddd'
|
||||
)}
|
||||
</Text>
|
||||
<Text>
|
||||
{menu[meaningfulStartingDate.isoWeekday() - 1]?.description}
|
||||
</Text>
|
||||
<Text>{menu[moment().isoWeekday() - 1]?.description}</Text>
|
||||
</>
|
||||
)}
|
||||
<View style={styles.itemFooterAbsence}>
|
||||
) : null}
|
||||
|
||||
<View style={styles.itemFooter}>
|
||||
<Button
|
||||
accessible
|
||||
accessibilityRole="button"
|
||||
|
@ -232,15 +278,16 @@ const themeStyles = StyleService.create({
|
|||
},
|
||||
itemFooter: {
|
||||
...Layout.flex.row,
|
||||
marginTop: Sizing.t4,
|
||||
},
|
||||
itemFooterAbsence: {
|
||||
...Layout.mainAxis.flexStart,
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-end',
|
||||
marginTop: Sizing.t4,
|
||||
},
|
||||
absenceButton: {
|
||||
marginLeft: -20,
|
||||
},
|
||||
itemFooterSpinner: {
|
||||
alignSelf: 'flex-end',
|
||||
},
|
||||
item: {
|
||||
marginRight: 12,
|
||||
paddingHorizontal: 2,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useNavigation } from '@react-navigation/core'
|
||||
import { Child } from '@skolplattformen/api-skolplattformen'
|
||||
import { Child } from '@skolplattformen/api'
|
||||
import { useApi, useChildList } from '@skolplattformen/hooks'
|
||||
import {
|
||||
Button,
|
||||
|
@ -10,7 +10,8 @@ import {
|
|||
TopNavigationAction,
|
||||
useStyleSheet,
|
||||
} from '@ui-kitten/components'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import moment from 'moment'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import {
|
||||
Image,
|
||||
ImageStyle,
|
||||
|
@ -24,7 +25,7 @@ import AppStorage from '../services/appStorage'
|
|||
import { Colors, Layout as LayoutStyle, Sizing, Typography } from '../styles'
|
||||
import { translate } from '../utils/translation'
|
||||
import { ChildListItem } from './childListItem.component'
|
||||
import { SettingsIcon } from './icon.component'
|
||||
import { SettingsIcon, RefreshIcon } from './icon.component'
|
||||
|
||||
const colors = ['primary', 'success', 'info', 'warning', 'danger']
|
||||
|
||||
|
@ -45,9 +46,12 @@ export const Children = () => {
|
|||
|
||||
const { api } = useApi()
|
||||
const { data: childList, status, reload } = useChildList()
|
||||
const reloadChildren = () => {
|
||||
const reloadChildren = useCallback(() => {
|
||||
reload()
|
||||
}
|
||||
setUpdated(moment().toISOString())
|
||||
}, [reload])
|
||||
|
||||
const [updatedAt, setUpdated] = useState('')
|
||||
|
||||
const logout = useCallback(() => {
|
||||
AppStorage.clearTemporaryItems().then(() => api.logout())
|
||||
|
@ -63,82 +67,87 @@ export const Children = () => {
|
|||
/>
|
||||
)
|
||||
},
|
||||
headerRight: () => {
|
||||
return (
|
||||
<TopNavigationAction
|
||||
icon={RefreshIcon}
|
||||
onPress={() => reloadChildren()}
|
||||
accessibilityHint="Reload"
|
||||
accessibilityLabel="Reload"
|
||||
/>
|
||||
)
|
||||
},
|
||||
})
|
||||
}, [navigation])
|
||||
}, [navigation, reloadChildren])
|
||||
|
||||
// We need to skip safe area view here, due to the reason that it's adding a white border
|
||||
// when this view is actually lightgrey. Taking the padding top value from the use inset hook.
|
||||
return (
|
||||
<>
|
||||
{status === 'loaded' ? (
|
||||
<List
|
||||
contentContainerStyle={styles.childListContainer}
|
||||
data={childList}
|
||||
style={styles.childList}
|
||||
ListEmptyComponent={
|
||||
<View style={styles.emptyState}>
|
||||
<Text category="h2">{translate('children.noKids_title')}</Text>
|
||||
<Text style={styles.emptyStateDescription}>
|
||||
{translate('children.noKids_description')}
|
||||
</Text>
|
||||
<Image
|
||||
accessibilityIgnoresInvertColors={false}
|
||||
source={require('../assets/children.png')}
|
||||
style={styles.emptyStateImage as ImageStyle}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
renderItem={({ item: child, index }: ListRenderItemInfo<Child>) => (
|
||||
<ChildListItem
|
||||
child={child}
|
||||
color={colors[index % colors.length]}
|
||||
key={child.id}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.loading}>
|
||||
return status === 'loaded' ? (
|
||||
<List
|
||||
contentContainerStyle={styles.childListContainer}
|
||||
data={childList}
|
||||
style={styles.childList}
|
||||
ListEmptyComponent={
|
||||
<View style={styles.emptyState}>
|
||||
<Text category="h2">{translate('children.noKids_title')}</Text>
|
||||
<Text style={styles.emptyStateDescription}>
|
||||
{translate('children.noKids_description')}
|
||||
</Text>
|
||||
<Image
|
||||
accessibilityIgnoresInvertColors={false}
|
||||
source={require('../assets/girls.png')}
|
||||
style={styles.loadingImage as ImageStyle}
|
||||
source={require('../assets/children.png')}
|
||||
style={styles.emptyStateImage as ImageStyle}
|
||||
/>
|
||||
{status === 'error' ? (
|
||||
<View style={styles.errorMessage}>
|
||||
<Text category="h5">
|
||||
{translate('children.loadingErrorHeading')}
|
||||
</Text>
|
||||
<Text style={{ fontSize: Sizing.t4 }}>
|
||||
{translate('children.loadingErrorInformationText')}
|
||||
</Text>
|
||||
<View style={styles.errorButtons}>
|
||||
<Button status="success" onPress={() => reloadChildren()}>
|
||||
{translate('children.tryAgain')}
|
||||
</Button>
|
||||
<Button
|
||||
status="basic"
|
||||
onPress={() =>
|
||||
Linking.openURL('https://skolplattformen.org/status')
|
||||
}
|
||||
>
|
||||
{translate('children.viewStatus')}
|
||||
</Button>
|
||||
<Button onPress={() => logout()}>
|
||||
{translate('general.logout')}
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingMessage}>
|
||||
<Spinner size="large" status="primary" />
|
||||
<Text category="h1" style={styles.loadingText}>
|
||||
{translate('general.loading')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
renderItem={({ item: child, index }: ListRenderItemInfo<Child>) => (
|
||||
<ChildListItem
|
||||
child={child}
|
||||
color={colors[index % colors.length]}
|
||||
updated={updatedAt}
|
||||
key={child.id}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.loading}>
|
||||
<Image
|
||||
accessibilityIgnoresInvertColors={false}
|
||||
source={require('../assets/girls.png')}
|
||||
style={styles.loadingImage as ImageStyle}
|
||||
/>
|
||||
{status === 'error' ? (
|
||||
<View style={styles.errorMessage}>
|
||||
<Text category="h5">{translate('children.loadingErrorHeading')}</Text>
|
||||
<Text style={{ fontSize: Sizing.t4 }}>
|
||||
{translate('children.loadingErrorInformationText')}
|
||||
</Text>
|
||||
<View style={styles.errorButtons}>
|
||||
<Button status="success" onPress={() => reloadChildren()}>
|
||||
{translate('children.tryAgain')}
|
||||
</Button>
|
||||
<Button
|
||||
status="basic"
|
||||
onPress={() =>
|
||||
Linking.openURL('https://skolplattformen.org/status')
|
||||
}
|
||||
>
|
||||
{translate('children.viewStatus')}
|
||||
</Button>
|
||||
<Button onPress={() => logout()}>
|
||||
{translate('general.logout')}
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingMessage}>
|
||||
<Spinner size="large" status="primary" />
|
||||
<Text category="h1" style={styles.loadingText}>
|
||||
{translate('general.loading')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -187,7 +196,6 @@ const themedStyles = StyleService.create({
|
|||
emptyState: {
|
||||
...LayoutStyle.center,
|
||||
...LayoutStyle.flex.full,
|
||||
backgroundColor: Colors.neutral.white,
|
||||
paddingHorizontal: Sizing.t5,
|
||||
},
|
||||
emptyStateDescription: {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Classmate } from '@skolplattformen/api-skolplattformen'
|
||||
import { Classmate } from '@skolplattformen/api'
|
||||
import { useClassmates } from '@skolplattformen/hooks'
|
||||
import {
|
||||
Divider,
|
||||
|
@ -9,7 +9,7 @@ import {
|
|||
Text,
|
||||
} from '@ui-kitten/components'
|
||||
import React from 'react'
|
||||
import { ListRenderItemInfo, StyleSheet } from 'react-native'
|
||||
import { ListRenderItemInfo, RefreshControl, StyleSheet } from 'react-native'
|
||||
import { fullName, guardians, sortByFirstName } from '../utils/peopleHelpers'
|
||||
import { translate } from '../utils/translation'
|
||||
import { useChild } from './childContext.component'
|
||||
|
@ -22,7 +22,7 @@ interface ClassmatesProps {
|
|||
export const Classmates = () => {
|
||||
const child = useChild()
|
||||
|
||||
const { data } = useClassmates(child)
|
||||
const { data, status, reload } = useClassmates(child)
|
||||
const renderItemIcon = (props: IconProps) => (
|
||||
<Icon {...props} name="people-outline" />
|
||||
)
|
||||
|
@ -60,6 +60,9 @@ export const Classmates = () => {
|
|||
}
|
||||
renderItem={renderItem}
|
||||
contentContainerStyle={styles.contentContainer}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={status === 'loading'} onRefresh={reload} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable react-native-a11y/has-accessibility-hint */
|
||||
import { Classmate } from '@skolplattformen/api-skolplattformen'
|
||||
import { Classmate } from '@skolplattformen/api'
|
||||
import {
|
||||
Button,
|
||||
MenuGroup,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Child } from '@skolplattformen/api-skolplattformen'
|
||||
import { Child } from '@skolplattformen/api'
|
||||
import { useTimetable } from '@skolplattformen/hooks'
|
||||
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
|
||||
import moment, { Moment } from 'moment'
|
||||
import React from 'react'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { LanguageService } from '../services/languageService'
|
||||
import { translate } from '../utils/translation'
|
||||
|
@ -12,9 +12,17 @@ interface DaySummaryProps {
|
|||
date?: Moment
|
||||
}
|
||||
|
||||
export const DaySummary = ({ child, date = moment() }: DaySummaryProps) => {
|
||||
const capitalizeFirstLetter = (string) => {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||
}
|
||||
|
||||
export const DaySummary = ({
|
||||
child,
|
||||
date: currentDate = moment(),
|
||||
}: DaySummaryProps) => {
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
const [year, week] = [moment().isoWeekYear(), moment().isoWeek()]
|
||||
const [week, year] = [currentDate.isoWeek(), currentDate.isoWeekYear()]
|
||||
|
||||
const { data: weekLessons } = useTimetable(
|
||||
child,
|
||||
week,
|
||||
|
@ -23,8 +31,8 @@ export const DaySummary = ({ child, date = moment() }: DaySummaryProps) => {
|
|||
)
|
||||
|
||||
const lessons = weekLessons
|
||||
.filter((lesson) => lesson.dayOfWeek === date.isoWeekday())
|
||||
.sort((a, b) => a.dateStart.localeCompare(b.dateStart))
|
||||
.filter((lesson) => lesson.dayOfWeek === currentDate.isoWeekday())
|
||||
.sort((a, b) => a.timeStart.localeCompare(b.timeStart))
|
||||
|
||||
if (lessons.length <= 0) {
|
||||
return null
|
||||
|
@ -34,6 +42,11 @@ export const DaySummary = ({ child, date = moment() }: DaySummaryProps) => {
|
|||
|
||||
return (
|
||||
<View>
|
||||
{moment().weekday() !== currentDate.weekday() ? (
|
||||
<Text category="c2" style={styles.weekday}>
|
||||
{capitalizeFirstLetter(currentDate.format('dddd'))}
|
||||
</Text>
|
||||
) : null}
|
||||
<View style={styles.summary}>
|
||||
<View style={styles.part}>
|
||||
<View>
|
||||
|
@ -49,19 +62,27 @@ export const DaySummary = ({ child, date = moment() }: DaySummaryProps) => {
|
|||
{translate('schedule.end')}
|
||||
</Text>
|
||||
<Text category="h5">
|
||||
{lessons[lessons.length - 1].timeEnd.slice(0, 5)}
|
||||
{lessons
|
||||
.sort((a, b) => a.timeEnd.localeCompare(b.timeEnd))
|
||||
[lessons.length - 1].timeEnd.slice(0, 5)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.part}>
|
||||
<View>
|
||||
<Text category="c2" style={styles.label}>
|
||||
|
||||
</Text>
|
||||
<Text category="s2">
|
||||
{gymBag
|
||||
? ` 🤼♀️ ${translate('schedule.gymBag', {
|
||||
defaultValue: 'Gympapåse',
|
||||
})}`
|
||||
: ''}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text category="s2">
|
||||
{gymBag
|
||||
? ` 🤼♀️ ${translate('schedule.gymBag', {
|
||||
defaultValue: 'Gympapåse',
|
||||
})}`
|
||||
: ''}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
@ -76,4 +97,11 @@ const themedStyles = StyleService.create({
|
|||
label: {
|
||||
marginTop: 10,
|
||||
},
|
||||
heading: {
|
||||
marginBottom: -10,
|
||||
},
|
||||
weekday: {
|
||||
marginBottom: -10,
|
||||
padding: 0,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -32,3 +32,4 @@ export const ClipboardIcon = uiIcon('clipboard-outline')
|
|||
export const RightArrowIcon = uiIcon('arrow-ios-forward-outline')
|
||||
export const QuestionMarkIcon = uiIcon('question-mark')
|
||||
export const AwardIcon = uiIcon('award')
|
||||
export const RefreshIcon = uiIcon('refresh')
|
||||
|
|
|
@ -31,7 +31,7 @@ export const Image = ({
|
|||
resizeMode = 'contain',
|
||||
}: ImageProps) => {
|
||||
const { api } = useApi()
|
||||
const [headers, setHeaders] = useState()
|
||||
const [headers, setHeaders] = useState<{ [index: string]: string }>()
|
||||
const { width: windowWidth } = useWindowDimensions()
|
||||
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
|
||||
|
||||
|
@ -40,7 +40,7 @@ export const Image = ({
|
|||
const prefetchImageInformation = useCallback(
|
||||
async (url: string) => {
|
||||
if (!url) return
|
||||
const { headers: newHeaders } = await api.getSession(url)
|
||||
const newHeaders = await api.getSessionHeaders(url)
|
||||
|
||||
console.log('[IMAGE] Getting image dimensions with headers', {
|
||||
debugImageName,
|
||||
|
|
|
@ -34,6 +34,7 @@ import {
|
|||
PersonIcon,
|
||||
SelectIcon,
|
||||
} from './icon.component'
|
||||
import AppStorage from '../services/appStorage'
|
||||
|
||||
const BankId = () => (
|
||||
<Image
|
||||
|
@ -88,6 +89,8 @@ export const Login = () => {
|
|||
] as const
|
||||
|
||||
const loginHandler = async () => {
|
||||
const user = await api.getUser()
|
||||
await AppStorage.clearPersonalData(user)
|
||||
showModal(false)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { MenuItem } from '@skolplattformen/api-skolplattformen'
|
||||
import { MenuItem } from '@skolplattformen/api'
|
||||
import { useMenu } from '@skolplattformen/hooks'
|
||||
import {
|
||||
Divider,
|
||||
|
@ -9,7 +9,13 @@ import {
|
|||
} from '@ui-kitten/components'
|
||||
import 'moment/locale/sv'
|
||||
import React from 'react'
|
||||
import { Image, ImageStyle, ListRenderItemInfo, View } from 'react-native'
|
||||
import {
|
||||
Image,
|
||||
ImageStyle,
|
||||
ListRenderItemInfo,
|
||||
RefreshControl,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
|
||||
import { translate } from '../utils/translation'
|
||||
import { useChild } from './childContext.component'
|
||||
|
@ -18,7 +24,7 @@ import { MenuListItem } from './menuListItem.component'
|
|||
export const Menu = () => {
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
const child = useChild()
|
||||
const { data } = useMenu(child)
|
||||
const { data, status, reload } = useMenu(child)
|
||||
|
||||
return (
|
||||
<List
|
||||
|
@ -42,6 +48,9 @@ export const Menu = () => {
|
|||
<MenuListItem key={item.title} item={item} />
|
||||
)}
|
||||
style={styles.container}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={status === 'loading'} onRefresh={reload} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { MenuItem } from '@skolplattformen/api-skolplattformen'
|
||||
import { MenuItem } from '@skolplattformen/api'
|
||||
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
|
||||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
|
|
|
@ -20,12 +20,12 @@ export const ModalWebView = ({
|
|||
const [modalVisible, setModalVisible] = React.useState(true)
|
||||
const { api } = useApi()
|
||||
const [title, setTitle] = React.useState('...')
|
||||
const [headers, setHeaders] = useState()
|
||||
const [headers, setHeaders] = useState<{ [index: string]: string }>()
|
||||
|
||||
useEffect(() => {
|
||||
const getHeaders = async (urlToGetSessionFor: string) => {
|
||||
if (sharedCookiesEnabled) return
|
||||
const { headers: newHeaders } = await api.getSession(urlToGetSessionFor)
|
||||
const newHeaders = await api.getSessionHeaders(urlToGetSessionFor)
|
||||
setHeaders(newHeaders)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { NavigationContainer } from '@react-navigation/native'
|
|||
import {
|
||||
Child as ChildType,
|
||||
NewsItem as NewsItemType,
|
||||
} from '@skolplattformen/api-skolplattformen'
|
||||
} from '@skolplattformen/api'
|
||||
import { useApi } from '@skolplattformen/hooks'
|
||||
import { useTheme } from '@ui-kitten/components'
|
||||
import { Library } from 'libraries.json'
|
||||
|
|
|
@ -5,7 +5,13 @@ import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
|
|||
import moment from 'moment'
|
||||
import 'moment/locale/sv'
|
||||
import React from 'react'
|
||||
import { Dimensions, ImageStyle, ScrollView, View } from 'react-native'
|
||||
import {
|
||||
Dimensions,
|
||||
ImageStyle,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
|
||||
import { defaultStackStyling } from '../design/navigationThemes'
|
||||
import { Layout, Sizing, Typography } from '../styles'
|
||||
|
@ -46,7 +52,7 @@ export const newsItemRouteOptions =
|
|||
|
||||
export const NewsItem = ({ route }: NewsItemProps) => {
|
||||
const { newsItem, child } = route.params
|
||||
const { data } = useNewsDetails(child, newsItem)
|
||||
const { data, status, reload } = useNewsDetails(child, newsItem)
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
const stylesMarkdown = useStyleSheet(themedStylesMarkdown)
|
||||
|
||||
|
@ -54,6 +60,9 @@ export const NewsItem = ({ route }: NewsItemProps) => {
|
|||
<ScrollView
|
||||
contentContainerStyle={styles.article}
|
||||
style={styles.scrollView}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={status === 'loading'} onRefresh={reload} />
|
||||
}
|
||||
>
|
||||
<Text maxFontSizeMultiplier={2} style={styles.title}>
|
||||
{newsItem.header}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useNews } from '@skolplattformen/hooks'
|
||||
import { Input, List, StyleService, useStyleSheet } from '@ui-kitten/components'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { TouchableOpacity, View } from 'react-native'
|
||||
import { TouchableOpacity, View, RefreshControl } from 'react-native'
|
||||
import { Sizing } from '../styles'
|
||||
import {
|
||||
renderSearchResultPreview,
|
||||
|
@ -15,7 +15,7 @@ import { NewsListItem } from './newsListItem.component'
|
|||
export const NewsList = () => {
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
const child = useChild()
|
||||
const { data } = useNews(child)
|
||||
const { data, status, reload } = useNews(child)
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const searchResults = useNewsListSearchResults(searchQuery)
|
||||
|
@ -62,6 +62,13 @@ export const NewsList = () => {
|
|||
{renderSearchResultPreview(searchResult)}
|
||||
</NewsListItem>
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={status === 'loading'}
|
||||
onRefresh={reload}
|
||||
tintColor={'color-basic-100'}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -74,6 +81,13 @@ export const NewsList = () => {
|
|||
data={data}
|
||||
ListHeaderComponent={header}
|
||||
renderItem={({ item }) => <NewsListItem key={item.id} item={item} />}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={status === 'loading'}
|
||||
onRefresh={reload}
|
||||
tintColor={'color-basic-100'}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { NewsItem } from '@skolplattformen/api-skolplattformen'
|
||||
import { NewsItem } from '@skolplattformen/api'
|
||||
import { StyleService, useStyleSheet } from '@ui-kitten/components'
|
||||
import moment from 'moment'
|
||||
import React, { ReactNode } from 'react'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Notification as NotificationType } from '@skolplattformen/api-skolplattformen'
|
||||
import { Notification as NotificationType } from '@skolplattformen/api'
|
||||
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
|
||||
import moment from 'moment'
|
||||
import React from 'react'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { useNotifications } from '@skolplattformen/hooks'
|
||||
import { List, StyleService, useStyleSheet } from '@ui-kitten/components'
|
||||
import React from 'react'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { Sizing } from '../styles'
|
||||
import { useChild } from './childContext.component'
|
||||
import { Notification } from './notification.component'
|
||||
|
@ -8,7 +9,7 @@ import { Notification } from './notification.component'
|
|||
export const NotificationsList = () => {
|
||||
const styles = useStyleSheet(themedStyles)
|
||||
const child = useChild()
|
||||
const { data } = useNotifications(child)
|
||||
const { data, status, reload } = useNotifications(child)
|
||||
|
||||
return (
|
||||
<List
|
||||
|
@ -18,6 +19,9 @@ export const NotificationsList = () => {
|
|||
renderItem={(info) => (
|
||||
<Notification key={info.item.id} item={info.item} />
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={status === 'loading'} onRefresh={reload} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CalendarItem } from '@skolplattformen/api-skolplattformen'
|
||||
import { CalendarItem } from '@skolplattformen/api'
|
||||
import { Button, MenuItem, OverflowMenu, Text } from '@ui-kitten/components'
|
||||
import React from 'react'
|
||||
import RNCalendarEvents from 'react-native-calendar-events'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { NavigationProp, useNavigation } from '@react-navigation/core'
|
||||
import { useApi } from '@skolplattformen/hooks'
|
||||
import { useApi, useUser } from '@skolplattformen/hooks'
|
||||
import React, { useCallback } from 'react'
|
||||
import { ScrollView } from 'react-native'
|
||||
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
|
||||
|
@ -28,14 +28,16 @@ export const SettingsScreen = () => {
|
|||
const langCode = LanguageService.getLanguageCode()
|
||||
const language = languages.find((l) => l.langCode === langCode)
|
||||
const { api } = useApi()
|
||||
const { data: user } = useUser()
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
await AppStorage.clearTemporaryItems()
|
||||
await AppStorage.clearPersonalData(user)
|
||||
await api.logout()
|
||||
navigation.reset({
|
||||
routes: [{ name: 'Login' }],
|
||||
})
|
||||
}, [api, navigation])
|
||||
}, [api, navigation, user])
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import {
|
||||
Child,
|
||||
MenuItem,
|
||||
TimetableEntry,
|
||||
} from '@skolplattformen/api-skolplattformen'
|
||||
import { Child, MenuItem, TimetableEntry } from '@skolplattformen/api'
|
||||
import { useMenu, useTimetable } from '@skolplattformen/hooks'
|
||||
import {
|
||||
List,
|
||||
|
@ -20,6 +16,8 @@ import { View } from 'react-native'
|
|||
import { LanguageService } from '../services/languageService'
|
||||
import { Sizing, Typography } from '../styles'
|
||||
import { TransitionView } from './transitionView.component'
|
||||
import { getMeaningfulStartingDate } from '../utils/calendarHelpers'
|
||||
import { translate } from '../utils/translation'
|
||||
|
||||
interface WeekProps {
|
||||
child: Child
|
||||
|
@ -111,10 +109,12 @@ export const Day = ({ weekDay, lunch, lessons }: DayProps) => {
|
|||
export const Week = ({ child }: WeekProps) => {
|
||||
moment.locale(LanguageService.getLocale())
|
||||
const days = moment.weekdaysShort().slice(1, 6)
|
||||
const currentDayIndex = Math.min(moment().isoWeekday() - 1, 5)
|
||||
const displayDate = getMeaningfulStartingDate(moment())
|
||||
|
||||
const currentDayIndex = Math.min(moment(displayDate).isoWeekday() - 1, 5)
|
||||
const [selectedIndex, setSelectedIndex] = useState(currentDayIndex)
|
||||
const [showSchema, setShowSchema] = useState(false)
|
||||
const [year, week] = [moment().isoWeekYear(), moment().isoWeek()]
|
||||
const [year, week] = [displayDate.isoWeekYear(), displayDate.isoWeek()]
|
||||
const { data: lessons } = useTimetable(
|
||||
child,
|
||||
week,
|
||||
|
@ -130,15 +130,30 @@ export const Week = ({ child }: WeekProps) => {
|
|||
setShowSchema(shouldShowSchema)
|
||||
}, [lessons])
|
||||
|
||||
const getWeekText = (date = moment()) => {
|
||||
return `${translate('schedule.week')} ${date.isoWeek()}`
|
||||
}
|
||||
|
||||
return showSchema ? (
|
||||
<TransitionView style={styles.view} animation={'fadeInDown'}>
|
||||
<TransitionView style={styles.innerView} animation={'fadeIn'}>
|
||||
<Text style={styles.weekNumber}>{getWeekText(displayDate)}</Text>
|
||||
<TabBar
|
||||
selectedIndex={selectedIndex}
|
||||
onSelect={(index) => setSelectedIndex(index)}
|
||||
>
|
||||
{days.map((weekDay) => (
|
||||
<Tab key={weekDay} title={weekDay} />
|
||||
{days.map((weekDay, index) => (
|
||||
<Tab
|
||||
key={weekDay}
|
||||
title={(_) => (
|
||||
<>
|
||||
<Text style={styles.tabTitle}>{weekDay}</Text>
|
||||
<Text style={styles.tabTitleDate}>
|
||||
{displayDate.startOf('week').add(index, 'day').format('D')}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</TabBar>
|
||||
|
||||
|
@ -154,7 +169,7 @@ export const Week = ({ child }: WeekProps) => {
|
|||
lunch={menu[index] || {}}
|
||||
lessons={lessons
|
||||
.filter((lesson) => days[lesson.dayOfWeek - 1] === weekDay)
|
||||
.sort((a, b) => a.dateStart.localeCompare(b.dateStart))}
|
||||
.sort((a, b) => a.timeStart.localeCompare(b.timeStart))}
|
||||
/>
|
||||
))}
|
||||
</ViewPager>
|
||||
|
@ -166,12 +181,12 @@ export const Week = ({ child }: WeekProps) => {
|
|||
const themedStyles = StyleService.create({
|
||||
view: {
|
||||
backgroundColor: 'background-basic-color-1',
|
||||
maxHeight: '60%',
|
||||
maxHeight: '65%',
|
||||
paddingBottom: 0,
|
||||
margin: 0,
|
||||
},
|
||||
innerView: {
|
||||
paddingBottom: 60,
|
||||
paddingBottom: 170,
|
||||
margin: 0,
|
||||
},
|
||||
part: {
|
||||
|
@ -233,4 +248,15 @@ const themedStyles = StyleService.create({
|
|||
lesson: {
|
||||
flexDirection: 'column',
|
||||
},
|
||||
weekNumber: {
|
||||
marginLeft: 10,
|
||||
marginTop: 10,
|
||||
...Typography.fontWeight.bold,
|
||||
},
|
||||
tabTitle: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
tabTitleDate: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
})
|
||||
|
|
|
@ -2,8 +2,9 @@ import { Features, FeatureType } from '@skolplattformen/api'
|
|||
import React from 'react'
|
||||
|
||||
export const FeatureFlagsContext = React.createContext<Features>({
|
||||
LOGIN_BANK_ID_SAME_DEVICE: false,
|
||||
LOGIN_BANK_ID_SAME_DEVICE_WITHOUT_ID: true,
|
||||
FOOD_MENU: false,
|
||||
CLASS_LIST: true,
|
||||
})
|
||||
|
||||
interface Props {
|
||||
|
|
|
@ -16,7 +16,7 @@ export const SchoolPlatformProvider: React.FC = ({ children }) => {
|
|||
'currentSchoolPlatform'
|
||||
)
|
||||
|
||||
const changeSchoolPlatform = (platform: string) => {
|
||||
const changeSchoolPlatform = (platform) => {
|
||||
setCurrentSchoolPlatform(platform)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ export const schoolPlatforms = [
|
|||
{
|
||||
id: 'stockholm-skolplattformen',
|
||||
displayName: 'Stockholm stad (Skolplattformen)',
|
||||
api: initSkolplattformen(fetch, CookieManager),
|
||||
api: initSkolplattformen(fetch as any, CookieManager),
|
||||
features: featuresSkolPlattformen,
|
||||
},
|
||||
{
|
||||
id: 'goteborg-hjarntorget',
|
||||
displayName: 'Göteborg stad (Hjärntorget)',
|
||||
api: initHjarntorget(fetch, CookieManager),
|
||||
api: initHjarntorget(fetch as any, CookieManager),
|
||||
features: featuresHjarntorget,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { User } from '@skolplattformen/api-skolplattformen'
|
||||
import { User } from '@skolplattformen/api'
|
||||
import { act, renderHook } from '@testing-library/react-hooks'
|
||||
import usePersonalStorage from '../usePersonalStorage'
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ import { useCallback } from 'react'
|
|||
import { proxy, subscribe, useSnapshot } from 'valtio'
|
||||
import AppStorage from '../services/appStorage'
|
||||
|
||||
export type ChildPersonalNumbers = Record<string, string>
|
||||
|
||||
export const settingsState = proxy({
|
||||
hydrated: false,
|
||||
settings: {
|
||||
|
@ -12,6 +14,7 @@ export const settingsState = proxy({
|
|||
currentSchoolPlatform: 'stockholm-skolplattformen' as
|
||||
| 'stockholm-skolplattformen'
|
||||
| 'goteborg-hjarntorget',
|
||||
childPersonalIdentityNumber: {} as ChildPersonalNumbers,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -669,4 +669,4 @@ SPEC CHECKSUMS:
|
|||
|
||||
PODFILE CHECKSUM: 85f5a2dfa1de342b427eecb6e9652410ad153247
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
COCOAPODS: 1.11.2
|
||||
|
|
|
@ -573,9 +573,9 @@
|
|||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/double-conversion/double-conversion.framework/double-conversion",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes/hermes.framework/hermes",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
|
@ -595,9 +595,9 @@
|
|||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/double-conversion/double-conversion.framework/double-conversion",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes/hermes.framework/hermes",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
|
@ -793,7 +793,7 @@
|
|||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = app/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 3.0.1;
|
||||
MARKETING_VERSION = 3.0.3;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
|
@ -822,7 +822,7 @@
|
|||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = app/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 3.0.1;
|
||||
MARKETING_VERSION = 3.0.3;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { User } from '@skolplattformen/api-skolplattformen'
|
||||
import { User } from '@skolplattformen/api'
|
||||
import AppStorage from '../appStorage'
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { User } from '@skolplattformen/api-skolplattformen'
|
||||
import { User } from '@skolplattformen/api'
|
||||
|
||||
export default class AppStorage {
|
||||
static settingsStorageKeyPrefix = 'appsetting_'
|
||||
|
|
|
@ -58,7 +58,9 @@
|
|||
"saveToCalender": "Save in calendar",
|
||||
"saveToCalenderError": "Something went wrong",
|
||||
"saveToCalenderSuccess": "✔️ Saved in calendar",
|
||||
"showCalenderActions": "Show calendar actions"
|
||||
"showCalenderActions": "Show calendar actions",
|
||||
"emptyHeadline": "The calendar looks kinda empty",
|
||||
"emptyText": "Couldn't find anything to show"
|
||||
},
|
||||
"children": {
|
||||
"loadingErrorHeading": "Oops!",
|
||||
|
@ -80,7 +82,8 @@
|
|||
"send": "Send",
|
||||
"settings": "Settings",
|
||||
"socialSecurityNumber": "Personal identity number",
|
||||
"title": "Öppna skolplattformen"
|
||||
"title": "Öppna skolplattformen",
|
||||
"tomorrow": "Tomorrow"
|
||||
},
|
||||
"language": {
|
||||
"changeLanguage": "Change language",
|
||||
|
@ -128,7 +131,8 @@
|
|||
"start": "Start",
|
||||
"end": "End",
|
||||
"lunch": "Lunch",
|
||||
"gymBag": "Gym bag"
|
||||
"gymBag": "Gym bag",
|
||||
"week": "Week"
|
||||
},
|
||||
"classmates": {
|
||||
"class": "Class",
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"changeLanguage": "Changer de langue",
|
||||
"cancel": "Annuler",
|
||||
"logoutAndClearPersonalData": "Se déconnecter et effacer les données personnelles",
|
||||
"logoutAndClearAllDataInclSettings": "Se déconnecter et effacer toutes les données, y compris les paramètres"
|
||||
"logoutAndClearAllDataInclSettings": "Se déconnecter et effacer toutes les données, y compris les paramètres",
|
||||
"tomorrow": "Demain"
|
||||
},
|
||||
"calender": {
|
||||
"saveToCalenderError": "Un problème est survenu",
|
||||
|
@ -53,7 +54,8 @@
|
|||
"a11y_select_login_method": "Sélectionnez la méthode de connexion",
|
||||
"a11y_clear_social_security_input_field": "Effacer le champ du numéro national d’identité",
|
||||
"a11y_image_two_boys": "Photo de deux personnes consultant leur téléphone portable",
|
||||
"a11y_change_language": "Sélectionnez votre langue"
|
||||
"a11y_change_language": "Sélectionnez votre langue",
|
||||
"chooseSchoolPlatform": "Choisir la plateforme"
|
||||
},
|
||||
"abscense": {
|
||||
"startTime": "Heure de début",
|
||||
|
|
|
@ -50,7 +50,9 @@
|
|||
"saveToCalenderSuccess": "✔️ Lagret i kalender",
|
||||
"showCalenderActions": "Vis kalenderhandlinger",
|
||||
"saveToCalenderError": "Noe gikk galt",
|
||||
"approveAccessToCalender": "Du må innvilge tilgang til kalenderen din"
|
||||
"approveAccessToCalender": "Du må innvilge tilgang til kalenderen din",
|
||||
"emptyHeadline": "Kalenderen ser tom ut",
|
||||
"emptyText": "Ingenting å vise"
|
||||
},
|
||||
"general": {
|
||||
"loading": "Laster inn …",
|
||||
|
@ -63,7 +65,8 @@
|
|||
"send": "Send",
|
||||
"cancel": "Avbryt",
|
||||
"logoutAndClearPersonalData": "Logg ut og tøm personlig data",
|
||||
"logoutAndClearAllDataInclSettings": "Logg ut og tøm all data, inkludert innstillinger"
|
||||
"logoutAndClearAllDataInclSettings": "Logg ut og tøm all data, inkludert innstillinger",
|
||||
"tomorrow": "I morgen"
|
||||
},
|
||||
"news": {
|
||||
"updated": "Oppdatert",
|
||||
|
@ -115,7 +118,8 @@
|
|||
"gymBag": "Gym-bag",
|
||||
"lunch": "Lunsj",
|
||||
"end": "Slutt",
|
||||
"start": "Start"
|
||||
"start": "Start",
|
||||
"week": "Uke"
|
||||
},
|
||||
"contact": {
|
||||
"a11y_show_contact_info_button_hint": "Vis kontaktinfo",
|
||||
|
|
|
@ -50,14 +50,17 @@
|
|||
"a11y_select_login_method": "Wybierz metodę logowania",
|
||||
"a11y_clear_social_security_input_field": "Wyczyść pole z personnumerem",
|
||||
"a11y_image_two_boys": "Ilustracja: dwie osoby patrzą w telefony komórkowe",
|
||||
"a11y_change_language": "Wybierz język"
|
||||
"a11y_change_language": "Wybierz język",
|
||||
"chooseSchoolPlatform": "Wybierz platformę"
|
||||
},
|
||||
"calender": {
|
||||
"approveAccessToCalender": "Musisz zatwierdzić dostęp do kalendarza",
|
||||
"saveToCalender": "Zapisz w kalendarzu",
|
||||
"saveToCalenderError": "Coś poszło nie tak",
|
||||
"saveToCalenderSuccess": "✔️ Zapisano w kalendarzu",
|
||||
"showCalenderActions": "Pokaż opcje kalendarza"
|
||||
"showCalenderActions": "Pokaż opcje kalendarza",
|
||||
"emptyHeadline": "Kalendarz jest pusty",
|
||||
"emptyText": "Nie znaleziono nic do pokazania"
|
||||
},
|
||||
"children": {
|
||||
"loadingErrorHeading": "Oj!",
|
||||
|
@ -79,7 +82,8 @@
|
|||
"title": "Öppna skolplattformen",
|
||||
"cancel": "Anuluj",
|
||||
"logoutAndClearPersonalData": "Wyloguj i skasuj dane osobowe",
|
||||
"logoutAndClearAllDataInclSettings": "Wyloguj i skasuj wszystkie dane łącznie z ustawieniami"
|
||||
"logoutAndClearAllDataInclSettings": "Wyloguj i skasuj wszystkie dane łącznie z ustawieniami",
|
||||
"tomorrow": "Jutro"
|
||||
},
|
||||
"language": {
|
||||
"changeLanguage": "Zmień język",
|
||||
|
@ -114,11 +118,12 @@
|
|||
"gymBag": "Ubrania do WF",
|
||||
"lunch": "Lunch",
|
||||
"end": "Kończy",
|
||||
"start": "Zaczyna"
|
||||
"start": "Zaczyna",
|
||||
"week": "Tydzień"
|
||||
},
|
||||
"contact": {
|
||||
"a11y_show_contact_info_button_hint": "Pokazuje dane kontaktowe",
|
||||
"home": "Dom",
|
||||
"home": "Adres",
|
||||
"email": "E-mail",
|
||||
"sms": "SMS",
|
||||
"call": "Zadzwoń",
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
"selectAbscenseEndTime": "Indique a hora de fim",
|
||||
"endTime": "Hora de fim",
|
||||
"invalidPersonalNumber": "Número de identidade pessoal inválido",
|
||||
"personalNumberMissing": "Falta o número de identidade pessoal"
|
||||
"personalNumberMissing": "Falta o número de identidade pessoal",
|
||||
"childsPersonalNumber": "Número de identidade pessoal da criança"
|
||||
},
|
||||
"auth": {
|
||||
"bankid": {
|
||||
|
|
|
@ -58,7 +58,9 @@
|
|||
"saveToCalender": "Spara till kalender",
|
||||
"saveToCalenderError": "Något gick fel",
|
||||
"saveToCalenderSuccess": "✔️ Sparad till kalender",
|
||||
"showCalenderActions": "Visa kalenderfunktioner"
|
||||
"showCalenderActions": "Visa kalenderfunktioner",
|
||||
"emptyText": "Hittade ingenting att visa",
|
||||
"emptyHeadline": "Det ser lite tomt ut i kalendern"
|
||||
},
|
||||
"children": {
|
||||
"loadingErrorHeading": "Hoppsan!",
|
||||
|
@ -80,7 +82,8 @@
|
|||
"title": "Öppna skolplattformen",
|
||||
"cancel": "Avbryt",
|
||||
"logoutAndClearAllDataInclSettings": "Logga ut och rensa all sparad data inkl inställningar",
|
||||
"logoutAndClearPersonalData": "Logga ut och rensa all personlig data"
|
||||
"logoutAndClearPersonalData": "Logga ut och rensa all personlig data",
|
||||
"tomorrow": "Imorgon"
|
||||
},
|
||||
"language": {
|
||||
"changeLanguage": "Byt språk",
|
||||
|
@ -128,7 +131,8 @@
|
|||
"start": "Börjar",
|
||||
"end": "Slutar",
|
||||
"lunch": "Lunch",
|
||||
"gymBag": "Gympapåse"
|
||||
"gymBag": "Gympapåse",
|
||||
"week": "Vecka"
|
||||
},
|
||||
"classmates": {
|
||||
"class": "Klass",
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import moment from 'moment'
|
||||
import { getMeaningfulStartingDate } from '../calendarHelpers'
|
||||
|
||||
const tuesdayMorning = moment('2021-11-30T08:20:00+0100')
|
||||
const tuesdayEvening = moment('2021-11-30T19:20:26+0100')
|
||||
const wednesdayEvening = moment('2021-12-01T19:20:26+0100')
|
||||
const fridayEvening = moment('2021-12-03T19:20:26+0100')
|
||||
const saturdayEvening = moment('2021-12-04T19:20:26+0100')
|
||||
const sundayEvening = moment('2021-12-05T19:20:26+0100')
|
||||
const mondayEvening = moment('2021-12-06T19:20:26+0100')
|
||||
|
||||
describe('getMeaningfulStartingDate should not touch inputdate', () => {
|
||||
const origDate = moment()
|
||||
const origDateClone = origDate.clone()
|
||||
getMeaningfulStartingDate(origDate)
|
||||
|
||||
expect(origDate).toEqual(origDateClone)
|
||||
})
|
||||
|
||||
describe('getMeaningfulStartingDate on weekends', () => {
|
||||
it('should give next monday if on friday evening', () => {
|
||||
const startDate = getMeaningfulStartingDate(fridayEvening)
|
||||
expect(startDate.toISOString()).toEqual(mondayEvening.toISOString())
|
||||
})
|
||||
|
||||
it('should give next monday if on saturday', () => {
|
||||
const startDate = getMeaningfulStartingDate(saturdayEvening)
|
||||
expect(startDate.toISOString()).toEqual(mondayEvening.toISOString())
|
||||
})
|
||||
|
||||
it('should give next monday if on sunday', () => {
|
||||
const startDate = getMeaningfulStartingDate(sundayEvening)
|
||||
expect(startDate.toISOString()).toEqual(mondayEvening.toISOString())
|
||||
})
|
||||
})
|
||||
|
||||
describe('getMeaningfulStartingDate on weekdays', () => {
|
||||
it('should give next day if on tuesday evening', () => {
|
||||
const startDate = getMeaningfulStartingDate(tuesdayEvening)
|
||||
expect(startDate.toISOString()).toEqual(wednesdayEvening.toISOString())
|
||||
})
|
||||
|
||||
it('should give same day if on tuesday morning', () => {
|
||||
const startDate = getMeaningfulStartingDate(tuesdayMorning)
|
||||
expect(startDate.toISOString()).toEqual(tuesdayMorning.toISOString())
|
||||
})
|
||||
})
|
|
@ -0,0 +1,18 @@
|
|||
import moment from 'moment'
|
||||
|
||||
export const getMeaningfulStartingDate = (date = moment()) => {
|
||||
const originalDate = date.clone()
|
||||
let returnDate = date.clone()
|
||||
// are we on the evening?
|
||||
if (date.hour() > 17) returnDate.add('1', 'day')
|
||||
// are we on the weekend
|
||||
if (returnDate.isoWeekday() > 5) {
|
||||
returnDate = returnDate.add(5, 'days').startOf('isoWeek')
|
||||
returnDate
|
||||
.hour(originalDate.hour())
|
||||
.minute(originalDate.minute())
|
||||
.second(originalDate.second())
|
||||
}
|
||||
|
||||
return returnDate
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { Guardian } from '@skolplattformen/api-skolplattformen'
|
||||
import { Guardian } from '@skolplattformen/api'
|
||||
|
||||
export const studentName = (name?: string) => name?.replace(/\s?\(\w+\)$/, '')
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { NewsItem } from '@skolplattformen/api-skolplattformen'
|
||||
import { NewsItem } from '@skolplattformen/api'
|
||||
import { useNews } from '@skolplattformen/hooks'
|
||||
import { MatchData, Searcher } from 'fast-fuzzy'
|
||||
import React, { ReactNode, useMemo } from 'react'
|
||||
|
|
|
@ -5,6 +5,7 @@ import { EvaIconsPack } from '@ui-kitten/eva-icons'
|
|||
import React, { ReactElement } from 'react'
|
||||
import { LanguageProvider } from '../context/language/languageContext'
|
||||
import { translations } from './translation'
|
||||
import { lightTheme } from '../design/themes'
|
||||
|
||||
export const render = (
|
||||
ui: ReactElement<any, string>,
|
||||
|
@ -14,7 +15,7 @@ export const render = (
|
|||
return (
|
||||
<>
|
||||
<IconRegistry icons={EvaIconsPack} />
|
||||
<ApplicationProvider {...eva} theme={eva.light}>
|
||||
<ApplicationProvider {...eva} theme={lightTheme}>
|
||||
<LanguageProvider
|
||||
cache={false}
|
||||
data={translations}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import CountUp from 'react-countup'
|
||||
import VisibilitySensor from 'react-visibility-sensor'
|
||||
import { price } from './Pricing'
|
||||
|
||||
const FUNFACTS_DATA = [
|
||||
{
|
||||
|
@ -12,7 +13,7 @@ const FUNFACTS_DATA = [
|
|||
title: 'år att utveckla',
|
||||
},
|
||||
{
|
||||
count: 11,
|
||||
count: price,
|
||||
title: 'kronor kostar vår app :)',
|
||||
},
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@ import DownloadButtons from './DownloadButtons'
|
|||
import Icon from './Icon'
|
||||
import SectionTitle from './SectionTitle'
|
||||
|
||||
const price = 12
|
||||
export const price = 11
|
||||
|
||||
const baseFeatures = [
|
||||
{
|
||||
|
|
|
@ -2,8 +2,7 @@ import { formatPrice } from '../utils/intl'
|
|||
import DownloadButtons from './DownloadButtons'
|
||||
import Icon from './Icon'
|
||||
import SectionTitle from './SectionTitle'
|
||||
|
||||
const price = 12
|
||||
import { price } from './Pricing'
|
||||
|
||||
const baseFeatures = [
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ const Privacy = () => {
|
|||
<p>
|
||||
"Öppna Skolplattformen", hädanefter "appen", byggs av "Not free beer
|
||||
AB" som en kommersiell app. Appen hämtar all information från
|
||||
Stockholms stads skolplattform, hädanefter Skolplattformen, efter
|
||||
respektive skolplattform, hädanefter Skolplattformen, efter
|
||||
inloggning via BankID. Appens funktion är därmed direkt knuten till
|
||||
att Skolplattformen fungerar. Vi kan endast ta ansvar för att vår kod
|
||||
fungerar – inte deras.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Link from './Link'
|
||||
|
||||
import { price } from './Pricing'
|
||||
|
||||
const QA = () => {
|
||||
return (
|
||||
<div className="header">
|
||||
|
@ -249,7 +251,7 @@ const QA = () => {
|
|||
de?
|
||||
</h3>
|
||||
<p>
|
||||
Appen kostar 12 kronor. Intäkten registreras i aktiebolaget Not Free
|
||||
Appen kostar {price} kronor. Intäkten registreras i aktiebolaget Not Free
|
||||
Beer som ägs av tre av utvecklarna och går till att täcka kostnader
|
||||
för inköp. Det täcker inte på långa vägar den tid vi lagt ner. Med en
|
||||
låg engångskostnad ökar vi chansen att vi orkar syssla med underhåll
|
||||
|
@ -315,7 +317,7 @@ const QA = () => {
|
|||
<h3>Kontakta oss</h3>
|
||||
<p>
|
||||
Tveka inte att kontakta oss. Skicka ett mail till{' '}
|
||||
<a href="mailto:info@skolplattformen.org">dev@skolplattformen.org</a>.
|
||||
<a href="mailto:info@skolplattformen.org">info@skolplattformen.org</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -66,7 +66,7 @@ export const FEATURES_DATA = [
|
|||
{
|
||||
title: 'Kan byggas ut till fler skolsystem',
|
||||
text:
|
||||
'Just nu stöds bara Stockholm Stads skolplattform men med din hjälp kan fler skolplattformar integreras så att du slipper logga in i flera appar om du har barn i olika skolor.',
|
||||
'Just nu stöds Stockholms och Göteborgs stads skolplattformar. Med din hjälp kan fler integreras så att du slipper använda flera appar om du har barn i olika skolor.',
|
||||
image: (
|
||||
<svg
|
||||
className="fill-current"
|
||||
|
|
|
@ -35,6 +35,9 @@ module.exports = {
|
|||
h3: {
|
||||
color: theme('colors.white'),
|
||||
},
|
||||
h4: {
|
||||
color: theme('colors.white'),
|
||||
},
|
||||
a: {
|
||||
color: theme('colors.indigo.500'),
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ import {
|
|||
NewsItem,
|
||||
Notification,
|
||||
ScheduleItem,
|
||||
SchoolContact,
|
||||
Skola24Child,
|
||||
Teacher,
|
||||
TimetableEntry,
|
||||
toMarkdown,
|
||||
URLSearchParams,
|
||||
|
@ -25,7 +27,7 @@ import { decode } from 'he'
|
|||
import { DateTime, FixedOffsetZone } from 'luxon'
|
||||
import * as html from 'node-html-parser'
|
||||
import { fakeFetcher } from './fake/fakeFetcher'
|
||||
import { checkStatus } from './loginStatus'
|
||||
import { checkStatus, DummyStatusChecker } from './loginStatus'
|
||||
import { extractMvghostRequestBody, parseCalendarItem } from './parse/parsers'
|
||||
import {
|
||||
beginBankIdUrl,
|
||||
|
@ -50,6 +52,7 @@ import {
|
|||
wallMessagesUrl,
|
||||
abscenseRegistrationUrl
|
||||
} from './routes'
|
||||
import parse from '@skolplattformen/curriculum'
|
||||
|
||||
function getDateOfISOWeek(week: number, year: number) {
|
||||
const simple = new Date(year, 0, 1 + (week - 1) * 7)
|
||||
|
@ -140,14 +143,16 @@ export class ApiHjarntorget extends EventEmitter implements Api {
|
|||
return this.personalNumber
|
||||
}
|
||||
|
||||
async setSessionCookie(sessionCookie: string): Promise<void> {
|
||||
await this.fetch('login-cookie', hjarntorgetUrl, {
|
||||
headers: {
|
||||
cookie: sessionCookie,
|
||||
},
|
||||
redirect: 'manual',
|
||||
})
|
||||
public async getSessionHeaders(url: string): Promise<{ [index: string]: string }> {
|
||||
const cookie = await this.cookieManager.getCookieString(url)
|
||||
return {
|
||||
cookie,
|
||||
}
|
||||
}
|
||||
|
||||
async setSessionCookie(sessionCookie: string): Promise<void> {
|
||||
this.cookieManager.setCookieString(sessionCookie, hjarntorgetUrl)
|
||||
|
||||
const user = await this.getUser()
|
||||
if (!user.isAuthenticated) {
|
||||
throw new Error('Session cookie is expired')
|
||||
|
@ -247,6 +252,21 @@ export class ApiHjarntorget extends EventEmitter implements Api {
|
|||
return Promise.resolve([])
|
||||
}
|
||||
|
||||
public async getTeachers(child: EtjanstChild): Promise<Teacher[]> {
|
||||
if (!this.isLoggedIn) {
|
||||
throw new Error('Not logged in...')
|
||||
}
|
||||
return Promise.resolve([])
|
||||
}
|
||||
|
||||
public async getSchoolContacts(child: EtjanstChild): Promise<SchoolContact[]> {
|
||||
if (!this.isLoggedIn) {
|
||||
throw new Error('Not logged in...')
|
||||
}
|
||||
return Promise.resolve([])
|
||||
}
|
||||
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async getNews(_child: EtjanstChild): Promise<NewsItem[]> {
|
||||
if (!this.isLoggedIn) {
|
||||
|
@ -452,9 +472,8 @@ export class ApiHjarntorget extends EventEmitter implements Api {
|
|||
zone: FixedOffsetZone.instance(l.endDate.timezoneOffsetMinutes),
|
||||
})
|
||||
return {
|
||||
...parse(l.title, _lang),
|
||||
id: l.id,
|
||||
code: l.title,
|
||||
name: l.title,
|
||||
teacher: l.bookedTeacherNames && l.bookedTeacherNames[0],
|
||||
location: l.location,
|
||||
timeStart: start.toISOTime().substring(0, 5),
|
||||
|
@ -462,7 +481,7 @@ export class ApiHjarntorget extends EventEmitter implements Api {
|
|||
dayOfWeek: start.toJSDate().getDay(),
|
||||
blockName: l.title,
|
||||
dateStart: start.toISODate(),
|
||||
dateEnd: start.toISODate(),
|
||||
dateEnd: end.toISODate(),
|
||||
} as TimetableEntry
|
||||
})
|
||||
}
|
||||
|
@ -492,13 +511,13 @@ export class ApiHjarntorget extends EventEmitter implements Api {
|
|||
|
||||
if((beginLoginRedirectResponse as any).url.endsWith("startPage.do")) {
|
||||
// already logged in!
|
||||
const emitter = new EventEmitter()
|
||||
const emitter = new DummyStatusChecker()
|
||||
setTimeout(() => {
|
||||
this.isLoggedIn = true
|
||||
emitter.emit('OK')
|
||||
this.emit('login')
|
||||
}, 50)
|
||||
return emitter as unknown as LoginStatusChecker;
|
||||
return emitter as LoginStatusChecker;
|
||||
}
|
||||
|
||||
console.log('prepping??? shibboleth')
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -28,10 +28,9 @@ const fetchMappings: { [name:string]: () => Response} = {
|
|||
'event-role-members-24-821': eventRoleMembers24,
|
||||
'calendars': calendars,
|
||||
'calendar-14241345': calendar_14241345,
|
||||
|
||||
}
|
||||
|
||||
export const fakeFetcher: Fetcher = (name: string, url: string, init?: any): Promise<Response> => {
|
||||
const responder = fetchMappings[name] ?? (() => {throw new Error("Request not faked for name: " + name)})
|
||||
return Promise.resolve(responder());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
import { toNamespacedPath } from "path";
|
||||
|
||||
// TODO: fix the startDate/endDate of all lessons
|
||||
export const lessons_133700_goteborgsstad = () => {
|
||||
const baseTime = 1636357800000;
|
||||
const baseDate = new Date(baseTime)
|
||||
const today = new Date()
|
||||
const currentHour = today.getHours()
|
||||
today.setHours(baseDate.getHours())
|
||||
today.setMinutes(baseDate.getMinutes())
|
||||
today.setSeconds(0)
|
||||
|
||||
const offset = Math.abs(baseTime - today.getTime())
|
||||
let offset = Math.abs(baseTime - today.getTime())
|
||||
const weekDay = today.getDay()
|
||||
|
||||
if(weekDay == 6 || (weekDay == 5 && currentHour >= 18)) offset = offset + 2 * 86400000
|
||||
if(weekDay == 0) offset = offset + 86400000
|
||||
if(weekDay > 0 && weekDay < 6 && currentHour >= 18) offset = offset + 86400000
|
||||
|
||||
return {
|
||||
"url": "https://hjarntorget.goteborg.se/api/schema/lessons?forUser=133700_goteborgsstad&startDateIso=2021-11-01&endDateIso=2021-11-08",
|
||||
"headers": {
|
||||
|
@ -206,14 +215,21 @@ export const lessons_133700_goteborgsstad = () => {
|
|||
}
|
||||
|
||||
export const lessons_123456_goteborgsstad = () => {
|
||||
const baseTime = 1636355400000;
|
||||
const baseTime = 1636357800000;
|
||||
const baseDate = new Date(baseTime)
|
||||
const today = new Date()
|
||||
const currentHour = today.getHours()
|
||||
today.setHours(baseDate.getHours())
|
||||
today.setMinutes(baseDate.getMinutes())
|
||||
today.setSeconds(0)
|
||||
|
||||
const offset = Math.abs(baseTime - today.getTime())
|
||||
|
||||
let offset = Math.abs(baseTime - today.getTime())
|
||||
const weekDay = today.getDay()
|
||||
|
||||
if(weekDay == 6 || (weekDay == 5 && currentHour >= 18)) offset = offset + 2 * 86400000
|
||||
if(weekDay == 0) offset = offset + 86400000
|
||||
if(weekDay > 0 && weekDay < 6 && currentHour >= 18) offset = offset + 86400000
|
||||
|
||||
return {
|
||||
"url": "https://hjarntorget.goteborg.se/api/schema/lessons?forUser=123456_goteborgsstad&startDateIso=2021-11-01&endDateIso=2021-11-08",
|
||||
"headers": {
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
pollStatusUrl,
|
||||
} from './routes'
|
||||
|
||||
export class HjarntorgetChecker extends EventEmitter {
|
||||
export class HjarntorgetChecker extends EventEmitter implements LoginStatusChecker {
|
||||
private fetcher: Fetcher
|
||||
|
||||
private basePollingUrl: string
|
||||
|
@ -120,3 +120,10 @@ export const checkStatus = (
|
|||
fetch: Fetcher,
|
||||
basePollingUrl: string
|
||||
): LoginStatusChecker => new HjarntorgetChecker(fetch, basePollingUrl)
|
||||
|
||||
export class DummyStatusChecker extends EventEmitter implements LoginStatusChecker {
|
||||
token = ""
|
||||
async cancel(): Promise<void> {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ the concrete implementation of fetch and cookie handler must be injected.
|
|||
#### react-native
|
||||
|
||||
```javascript
|
||||
import init from '@skolplattformen/api-skolplattformen'
|
||||
import init from '@skolplattformen/api'
|
||||
import CookieManager from '@react-native-cookies/cookies'
|
||||
|
||||
const api = init(fetch, () => CookieManager.clearAll())
|
||||
|
@ -25,7 +25,7 @@ const api = init(fetch, () => CookieManager.clearAll())
|
|||
#### node
|
||||
|
||||
```javascript
|
||||
import init from '@skolplattformen/api-skolplattformen'
|
||||
import init from '@skolplattformen/api'
|
||||
import nodeFetch from 'node-fetch'
|
||||
import fetchCookie from 'fetch-cookie/node-fetch'
|
||||
import { CookieJar } from 'tough-cookie'
|
||||
|
|
|
@ -17,7 +17,9 @@ import {
|
|||
ScheduleItem,
|
||||
Skola24Child,
|
||||
SSOSystem,
|
||||
Teacher,
|
||||
TimetableEntry,
|
||||
SchoolContact,
|
||||
URLSearchParams,
|
||||
User,
|
||||
wrap,
|
||||
|
@ -28,7 +30,7 @@ import { decode } from 'he'
|
|||
import { DateTime } from 'luxon'
|
||||
import * as html from 'node-html-parser'
|
||||
import * as fake from './fakeData'
|
||||
import { checkStatus } from './loginStatusChecker'
|
||||
import { checkStatus, DummyStatusChecker } from './loginStatusChecker'
|
||||
import * as parse from './parse/index'
|
||||
import * as routes from './routes'
|
||||
|
||||
|
@ -97,6 +99,16 @@ export class ApiSkolplattformen extends EventEmitter implements Api {
|
|||
}
|
||||
}
|
||||
|
||||
public async getSessionHeaders(url: string): Promise<{ [index: string]: string }> {
|
||||
const init = this.getRequestInit()
|
||||
const cookie = await this.cookieManager.getCookieString(url)
|
||||
return {
|
||||
...init.headers,
|
||||
cookie,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async getSession(
|
||||
url: string,
|
||||
options?: RequestInit
|
||||
|
@ -206,8 +218,7 @@ export class ApiSkolplattformen extends EventEmitter implements Api {
|
|||
this.emit('login')
|
||||
}, 50)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const emitter: any = new EventEmitter()
|
||||
const emitter = new DummyStatusChecker()
|
||||
emitter.token = 'fake'
|
||||
return emitter
|
||||
}
|
||||
|
@ -265,6 +276,39 @@ export class ApiSkolplattformen extends EventEmitter implements Api {
|
|||
return parse.classmates(data)
|
||||
}
|
||||
|
||||
public async getTeachers(child: EtjanstChild): Promise<Teacher[]> {
|
||||
if (this.isFake) return fakeResponse(fake.teachers(child))
|
||||
|
||||
const session = this.getRequestInit()
|
||||
|
||||
const schoolForms = (child.status || '').split(';')
|
||||
let teachers: Teacher[] = []
|
||||
|
||||
for(let i = 0; i< schoolForms.length; i+=1){
|
||||
const url = routes.teachers(child.sdsId, schoolForms[i])
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const response = await this.fetch(`teachers_${schoolForms[i]}`, url, session)
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const data = await response.json()
|
||||
teachers = [
|
||||
...teachers,
|
||||
...parse.teachers(data)
|
||||
]
|
||||
}
|
||||
|
||||
return teachers
|
||||
}
|
||||
|
||||
public async getSchoolContacts(child: EtjanstChild): Promise<SchoolContact[]> {
|
||||
if(this.isFake) return fakeResponse(fake.schoolContacts(child))
|
||||
|
||||
const url = routes.schoolContacts(child.sdsId, child.schoolId || '')
|
||||
const session = this.getRequestInit()
|
||||
const response = await this.fetch('schoolContacts', url, session)
|
||||
const data = await response.json()
|
||||
return parse.schoolContacts(data)
|
||||
}
|
||||
|
||||
public async getSchedule(
|
||||
child: EtjanstChild,
|
||||
from: DateTime,
|
||||
|
@ -518,6 +562,8 @@ export class ApiSkolplattformen extends EventEmitter implements Api {
|
|||
return parse.timetable(json, year, week, lang)
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async logout() {
|
||||
this.isFake = false
|
||||
this.personalNumber = undefined
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,29 @@
|
|||
import { EtjanstChild, Skola24Child } from "@skolplattformen/api"
|
||||
|
||||
export const children = (): EtjanstChild[] => [
|
||||
{
|
||||
name: 'Shanel Nilsson (elev)',
|
||||
id: '39b59e-bf4b9f-f68ac25321-977218-bf0',
|
||||
sdsId: '8e81a06-53f55fb-d1b93-f0e5b357ad0b7caaf1d36',
|
||||
status: 'F;GR',
|
||||
schoolId: '9e58434-8800-da59547-614bf0e-e09c015',
|
||||
},
|
||||
{
|
||||
name: 'Alan Nilsson (elev)',
|
||||
id: 'eea96a-a3e045-caab589391-ed7d17-029',
|
||||
sdsId: 'bc2d341-8d970cc-69526-43501c082aaa870d9fe99',
|
||||
status: 'GR',
|
||||
schoolId: '8e6b13b-3116-e66c39b-a4c3fa5-a1d72d9',
|
||||
},
|
||||
]
|
||||
export const skola24Children = (): Skola24Child[] => [
|
||||
{
|
||||
firstName: 'Shanel',
|
||||
lastName: 'Jonsson Nilsson',
|
||||
personGuid: 'abc123',
|
||||
schoolGuid: 'def456',
|
||||
schoolID: 'Superskolan',
|
||||
timetableID: 'jkl012',
|
||||
unitGuid: 'mno345'
|
||||
},
|
||||
]
|
|
@ -0,0 +1,448 @@
|
|||
import { Child, Classmate } from '@skolplattformen/api';
|
||||
import { children } from './children'
|
||||
|
||||
export const classmates = (child: Child): Classmate[] => classmatesData.get(child.id) ?? []
|
||||
|
||||
const [child1, child2] = children()
|
||||
|
||||
const classmatesData = new Map<string, Classmate[]>([
|
||||
[
|
||||
child1.id, [
|
||||
{
|
||||
sisId: 'd004a-98d965a-45174-d2894ca2-f74ebcb',
|
||||
firstname: 'Darion',
|
||||
lastname: 'Gustafsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Mike_Svensson@example.net',
|
||||
firstname: 'Tad',
|
||||
lastname: 'Eriksson',
|
||||
mobile: '07074791613',
|
||||
address: 'Martinvägen 50',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: '54075-284de06-5664c-750b7b13-520fb61',
|
||||
firstname: 'Brock',
|
||||
lastname: 'Andersson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Brad56@example.org',
|
||||
firstname: 'Camren',
|
||||
lastname: 'Eriksson',
|
||||
mobile: '07075129297',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: 'c1fc7-285f95d-c0f37-ea48a297-281e985',
|
||||
firstname: 'Eloy',
|
||||
lastname: 'Karlsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Samara.Larsson@example.net',
|
||||
firstname: 'Ike',
|
||||
lastname: 'Gustafsson',
|
||||
mobile: '07077667407',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: '212e9-8a2609c-b29c1-97a32bd8-5f84645',
|
||||
firstname: 'Kristina',
|
||||
lastname: 'Eriksson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Doug57@example.com',
|
||||
firstname: 'Rollin',
|
||||
lastname: 'Olsson',
|
||||
mobile: '07071720107',
|
||||
address: 'Höckertsvägen 2',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: '01d21-ebc6f8b-526f8-7cfba0ab-26b9956',
|
||||
firstname: 'Cydney',
|
||||
lastname: 'Larsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Davon6@example.org',
|
||||
firstname: 'Oleta',
|
||||
lastname: 'Svensson',
|
||||
mobile: '07079762186',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: 'a45bb-8a481af-0ad12-7bd1fa4c-1eed4b1',
|
||||
firstname: 'Berneice',
|
||||
lastname: 'Persson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Milford_Johansson72@example.com',
|
||||
firstname: 'Arely',
|
||||
lastname: 'Johansson',
|
||||
mobile: '07071926019',
|
||||
address: 'Roslinvägen 36',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: '32f31-039fbed-9060b-2d857c46-e47177d',
|
||||
firstname: 'Emory',
|
||||
lastname: 'Svensson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Alfredo_Nilsson96@example.org',
|
||||
firstname: 'Dolores',
|
||||
lastname: 'Andersson',
|
||||
mobile: '070752561937',
|
||||
address: 'Börjesonsvägen 6',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: 'c9d0a-28c371d-e7be2-9781386b-6841eb0',
|
||||
firstname: 'Maryjane',
|
||||
lastname: 'Eriksson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Eula_Olsson@example.net',
|
||||
firstname: 'Wendy',
|
||||
lastname: 'Andersson',
|
||||
mobile: '07078513037',
|
||||
address: undefined,
|
||||
},
|
||||
{
|
||||
email: 'Lesley_Persson45@example.org',
|
||||
firstname: 'Erich',
|
||||
lastname: 'Persson',
|
||||
mobile: '070788191316',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: 'e0f51-3fbd0be-5a8c3-ded7bbed-1d655d5',
|
||||
firstname: 'Rosendo',
|
||||
lastname: 'Eriksson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Mitchell.Gustafsson84@example.org',
|
||||
firstname: 'Mariam',
|
||||
lastname: 'Johansson',
|
||||
mobile: '07074537423',
|
||||
address: 'Molinvägen 29',
|
||||
},
|
||||
{
|
||||
email: 'Rachelle_Olsson@example.net',
|
||||
firstname: 'Shaniya',
|
||||
lastname: 'Persson',
|
||||
mobile: '070765878480',
|
||||
address: 'Molinvägen 29',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: '298c2-46a24d4-548b9-3d1f90ee-4fae0ab',
|
||||
firstname: 'Sammy',
|
||||
lastname: 'Persson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Gloria_Svensson@example.com',
|
||||
firstname: 'Simeon',
|
||||
lastname: 'Olsson',
|
||||
mobile: '070753525610',
|
||||
address: 'Börjesonsvägen 43',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: 'e7628-09352ea-b5d19-1af845b7-63b3e08',
|
||||
firstname: 'Abraham',
|
||||
lastname: 'Svensson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Erica_Johansson40@example.net',
|
||||
firstname: 'Carlotta',
|
||||
lastname: 'Nilsson',
|
||||
mobile: '070737951712',
|
||||
address: 'Aroseniusvägen 27',
|
||||
},
|
||||
{
|
||||
email: 'Malcolm_Gustafsson55@example.org',
|
||||
firstname: 'Ramon',
|
||||
lastname: 'Persson',
|
||||
mobile: '07070395626',
|
||||
address: 'Aroseniusvägen 27',
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: 'ae315-4696438-b3db6-8f0a5b39-74e34bd',
|
||||
firstname: 'Devante',
|
||||
lastname: 'Olsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Alf.Johansson39@example.com',
|
||||
firstname: 'Schuyler',
|
||||
lastname: 'Gustafsson',
|
||||
mobile: '07070724289',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
{
|
||||
sisId: '0d812-350f1d5-323aa-d5d93cdd-406e337',
|
||||
firstname: 'Tyrell',
|
||||
lastname: 'Eriksson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Brennon.Svensson@example.com',
|
||||
firstname: 'Belle',
|
||||
lastname: 'Nilsson',
|
||||
mobile: '07070137347',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '2B',
|
||||
},
|
||||
]],
|
||||
[
|
||||
child2.id, [
|
||||
{
|
||||
sisId: '9ee9e-312233c-0df98-05fa5a65-a3787ec',
|
||||
firstname: 'Raphael',
|
||||
lastname: 'Olsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Johan99@example.com',
|
||||
firstname: 'Alessandra',
|
||||
lastname: 'Svensson',
|
||||
mobile: '070767120463',
|
||||
address: 'Franklandsvägen 34',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: 'd3a4b-16b53de-63c22-56d1ad24-4a64a2d',
|
||||
firstname: 'Fanny',
|
||||
lastname: 'Karlsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Bernadette.Eriksson@example.org',
|
||||
firstname: 'Bernadette',
|
||||
lastname: 'Karlsson',
|
||||
mobile: '070759877956',
|
||||
address: undefined,
|
||||
},
|
||||
{
|
||||
email: 'Candice29@example.net',
|
||||
firstname: 'Kelley',
|
||||
lastname: 'Gustafsson',
|
||||
mobile: '070748592035',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '42bde-8fabd1c-7a00e-28aea88a-8481bac',
|
||||
firstname: 'Jamie',
|
||||
lastname: 'Persson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Louisa82@example.net',
|
||||
firstname: 'Mose',
|
||||
lastname: 'Larsson',
|
||||
mobile: '07076548362',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: 'dad49-74308c8-83612-5eb7f3a5-e1c4047',
|
||||
firstname: 'Iris',
|
||||
lastname: 'Eriksson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Vaughn90@example.net',
|
||||
firstname: 'Ezra',
|
||||
lastname: 'Andersson',
|
||||
mobile: '07078700165',
|
||||
address: 'Björnsonsgatan 251 D Lgh 1503',
|
||||
},
|
||||
{
|
||||
email: 'Stephany_Svensson22@example.net',
|
||||
firstname: 'Mia',
|
||||
lastname: 'Larsson',
|
||||
mobile: '070761752378',
|
||||
address: 'Björnsonsgatan 251 D Lgh 1503',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: 'b3425-ada6d70-d3acc-a49a12a6-8b3afdc',
|
||||
firstname: 'Evans',
|
||||
lastname: 'Nilsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Terry_Svensson@example.com',
|
||||
firstname: 'Christop',
|
||||
lastname: 'Olsson',
|
||||
mobile: '070767660094',
|
||||
address: undefined,
|
||||
},
|
||||
{
|
||||
email: 'Johanna_Svensson30@example.org',
|
||||
firstname: 'Madisen',
|
||||
lastname: 'Johansson',
|
||||
mobile: '07072269029',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '67471-6c03979-9ef6e-bb2827c4-96d00d5',
|
||||
firstname: 'Evy',
|
||||
lastname: 'Larsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Serenity.Gustafsson@example.net',
|
||||
firstname: 'Toni',
|
||||
lastname: 'Larsson',
|
||||
mobile: '07075211567',
|
||||
address: 'Roslinvägen 48',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: 'f4040-516c4ed-34555-fd525183-6a2f666',
|
||||
firstname: 'Maximillia',
|
||||
lastname: 'Karlsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Faustino.Andersson@example.com',
|
||||
firstname: 'Eriberto',
|
||||
lastname: 'Nilsson',
|
||||
mobile: '07076024039',
|
||||
address: 'Beckombergavägen 213 Lgh 1304',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: 'a9494-75d8ca7-a5fd4-977eca3c-40edbc1',
|
||||
firstname: 'Pia',
|
||||
lastname: 'Karlsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Arthur.Karlsson4@example.org',
|
||||
firstname: 'Eldred',
|
||||
lastname: 'Svensson',
|
||||
mobile: '07077609534',
|
||||
address: 'Börjesonsvägen 6',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '42a6d-3eaf407-fed01-4a9538de-b822503',
|
||||
firstname: 'Logan',
|
||||
lastname: 'Larsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Blake4@example.org',
|
||||
firstname: 'Jan',
|
||||
lastname: 'Karlsson',
|
||||
mobile: '070728715653',
|
||||
address: 'Bällstavägen 162',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '9077d-c323c8d-d0d29-5690abfb-d348317',
|
||||
firstname: 'Torun',
|
||||
lastname: 'Eriksson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Blanca98@example.net',
|
||||
firstname: 'Dallin',
|
||||
lastname: 'Eriksson',
|
||||
mobile: '070766214425',
|
||||
address: 'Molinvägen 1',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '31c68-5b86667-0701d-6b7e2471-89e6df9',
|
||||
firstname: 'Izabella',
|
||||
lastname: 'Johansson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Elouise_Johansson25@example.org',
|
||||
firstname: 'Jerrold',
|
||||
lastname: 'Nilsson',
|
||||
mobile: '07073789274',
|
||||
address: 'Stobaeusvägen 11',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '1bb69-5f1c3a6-f0ea8-e1dbb608-2756a52',
|
||||
firstname: 'Ella',
|
||||
lastname: 'Persson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Shayna.Olsson54@example.net',
|
||||
firstname: 'Onie',
|
||||
lastname: 'Nilsson',
|
||||
mobile: '07076957797',
|
||||
address: undefined,
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
},
|
||||
{
|
||||
sisId: '348a7-2d0eccc-02981-a02ccb03-cb2a8f2',
|
||||
firstname: 'Jaylen',
|
||||
lastname: 'Larsson',
|
||||
guardians: [
|
||||
{
|
||||
email: 'Aileen_Andersson@example.net',
|
||||
firstname: 'Tess',
|
||||
lastname: 'Karlsson',
|
||||
mobile: '070715315590',
|
||||
address: 'Peringskiöldsvägen 64',
|
||||
},
|
||||
],
|
||||
className: '8C',
|
||||
}
|
||||
],
|
||||
]
|
||||
])
|
|
@ -0,0 +1,509 @@
|
|||
import { fourDaysAgo, oneDayAgo, oneWeekAgo } from './dates';
|
||||
/* eslint-disable max-len */
|
||||
import {
|
||||
CalendarItem,
|
||||
Child,
|
||||
Notification,
|
||||
ScheduleItem,
|
||||
User,
|
||||
} from '@skolplattformen/api';
|
||||
import { oneDayForward, oneWeekForward, twoDaysForward } from './dates';
|
||||
|
||||
const data: any = {
|
||||
'39b59e-bf4b9f-f68ac25321-977218-bf0': {
|
||||
calendar: [
|
||||
{
|
||||
title: 'Terminslut',
|
||||
id: 73,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2020-12-18',
|
||||
endDate: '2020-12-18',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Terminen börjar',
|
||||
id: 74,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-01-12',
|
||||
endDate: '2021-01-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT - fritids stänger 15:45',
|
||||
id: 75,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-01-21',
|
||||
endDate: '2021-01-21',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Utvecklingsamtal',
|
||||
id: 76,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-04',
|
||||
endDate: '2021-02-04',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Vänliga veckan',
|
||||
id: 77,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-08',
|
||||
endDate: '2021-02-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Utvecklingsamtal',
|
||||
id: 79,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-09',
|
||||
endDate: '2021-02-09',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Trygghetsdag',
|
||||
id: 78,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-12',
|
||||
endDate: '2021-02-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT fritids stänger 15:45',
|
||||
id: 80,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-25',
|
||||
endDate: '2021-02-25',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Sportlov',
|
||||
id: 81,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-03-01',
|
||||
endDate: '2021-03-05',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Studiedag',
|
||||
id: 82,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: oneWeekForward.startOf('day').toISODate(),
|
||||
endDate: oneWeekForward.endOf('day').toISODate(),
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT - fritids stänger 15:45',
|
||||
id: 83,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-01',
|
||||
endDate: '2021-04-01',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Långfredag',
|
||||
id: 84,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-02',
|
||||
endDate: '2021-04-02',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Påsklov',
|
||||
id: 85,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-05',
|
||||
endDate: '2021-04-09',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Föräldraråd',
|
||||
id: 86,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-20',
|
||||
endDate: '2021-04-20',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Prao åk 8',
|
||||
id: 97,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-26',
|
||||
endDate: '2021-05-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Kristi Himmelfärd',
|
||||
id: 87,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-05-13',
|
||||
endDate: '2021-05-13',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Lov',
|
||||
id: 88,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-05-14',
|
||||
endDate: '2021-05-14',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT Fritids stänger 15:45',
|
||||
id: 90,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-05-20',
|
||||
endDate: '2021-05-20',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Läsårsslut',
|
||||
id: 91,
|
||||
description:
|
||||
"<html><head><style>\r\np.MsoNormal, li.MsoNormal, div.MsoNormal {\nmargin:0cm;\nmargin-bottom:.0001pt;\nfont-size:11.0pt;\nfont-family:'Calibri',sans-serif;\n}\n\na:link, span.MsoHyperlink {\ncolor:#0563C1;\ntext-decoration:underline;\n}\n\nspan.MsoHyperlinkFollowed {\ncolor:#954F72;\ntext-decoration:underline;\n}\n\nspan.E-postmall17 {\nfont-family:'Calibri',sans-serif;\ncolor:windowtext;\n}\n\n.MsoChpDefault {\nfont-family:'Calibri',sans-serif;\n}\n\ndiv.WordSection1 {\n}\n\r\n</style></head><body lang='SV' link='#0563C1' vlink='#954F72' style=''><div class='WordSection1'><p class='MsoNormal'> </p></div></body></html>",
|
||||
location: null,
|
||||
startDate: '2021-06-11',
|
||||
endDate: '2021-06-11',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Fritids stängt',
|
||||
id: 92,
|
||||
description:
|
||||
"<html><head><style>\r\np.MsoNormal, li.MsoNormal, div.MsoNormal {\nmargin:0cm;\nmargin-bottom:.0001pt;\nfont-size:11.0pt;\nfont-family:'Calibri',sans-serif;\n}\n\na:link, span.MsoHyperlink {\ncolor:#0563C1;\ntext-decoration:underline;\n}\n\nspan.MsoHyperlinkFollowed {\ncolor:#954F72;\ntext-decoration:underline;\n}\n\nspan.E-postmall17 {\nfont-family:'Calibri',sans-serif;\ncolor:windowtext;\n}\n\n.MsoChpDefault {\nfont-family:'Calibri',sans-serif;\n}\n\ndiv.WordSection1 {\n}\n\r\n</style></head><body lang='SV' link='#0563C1' vlink='#954F72' style=''><div class='WordSection1'><p class='MsoNormal'> </p></div></body></html>",
|
||||
location: null,
|
||||
startDate: '2021-06-14',
|
||||
endDate: '2021-06-14',
|
||||
allDay: true,
|
||||
},
|
||||
],
|
||||
schedule: [
|
||||
{
|
||||
title: 'Läsläxan tillbaka',
|
||||
description: 'Ta med boken tillbaka till skolan',
|
||||
location: '',
|
||||
allDayEvent: false,
|
||||
startDate: oneDayForward.startOf('day').toISO(),
|
||||
endDate: oneDayForward.endOf('day').toISO(),
|
||||
oneDayEvent: true
|
||||
} as ScheduleItem
|
||||
],
|
||||
notifications: [
|
||||
{
|
||||
id: 'bfe19b-766db3-b38d99d321-bbed3d-506',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: oneDayAgo.minus({months: 6}).toISO(),
|
||||
dateModified: fourDaysAgo.toISO(),
|
||||
message: 'Ett nytt inlägg i en lärlogg har skapats.',
|
||||
url:
|
||||
'https://www.breakit.se/artikel/21423/har-ar-it-bolaget-bakom-haveriet-pa-skolplattformen',
|
||||
category: 'Lärlogg',
|
||||
type: 'avisering',
|
||||
},
|
||||
{
|
||||
id: '9025f9-a1e685-d7c4668f09-e14bc5-0ab',
|
||||
sender: 'Elevdokumentation',
|
||||
dateCreated: '2020-12-10T14:31:29.966Z',
|
||||
message:
|
||||
'Nu kan du ta del av ditt barns dokumentation av utvecklingssamtal',
|
||||
url:
|
||||
'https://www.breakit.se/artikel/21404/kodaren-slog-larm-nu-akutstoppas-skolplattformen-i-stockholm',
|
||||
category: null,
|
||||
type: 'webnotify',
|
||||
},
|
||||
{
|
||||
id: 'a24061-1c9a4e-83dc479d7c-f44fe9-376',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-06-10T12:18:00.000Z',
|
||||
message: 'Nu finns det en bedömning att titta på.',
|
||||
url:
|
||||
'https://www.svt.se/nyheter/lokalt/stockholm/skolplattformen-i-stockholm-beratta-om-era-erfarenheter',
|
||||
category: 'Bedömning',
|
||||
type: 'avisering',
|
||||
},
|
||||
{
|
||||
id: '79d65c-1f8240-35c94296ec-9f4bdc-cea',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-03-24T14:28:00.000Z',
|
||||
message: 'Nu finns det en bedömning att titta på.',
|
||||
url:
|
||||
'https://www.breakit.se/artikel/18120/skolplattformen-kostade-700-miljoner-strid-med-entreprenor-om-varumarket',
|
||||
category: 'Bedömning',
|
||||
type: 'avisering',
|
||||
},
|
||||
{
|
||||
id: '9c5b7b-52c16d-b9fc2e8248-e4de76-279',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-03-24T13:48:00.000Z',
|
||||
message: 'Nu finns det en bedömning att titta på.',
|
||||
url:
|
||||
'https://www.mitti.se/nyheter/forskolans-tur-att-fa-kritiserade-skolplattformen-app/lmsau!5338007/',
|
||||
category: 'Bedömning',
|
||||
type: 'avisering',
|
||||
},
|
||||
],
|
||||
},
|
||||
'eea96a-a3e045-caab589391-ed7d17-029': {
|
||||
calendar: [
|
||||
{
|
||||
title: 'Terminslut',
|
||||
id: 73,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2020-12-18',
|
||||
endDate: '2020-12-18',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Terminen börjar',
|
||||
id: 74,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-01-12',
|
||||
endDate: '2021-01-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT - fritids stänger 15:45',
|
||||
id: 75,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: oneWeekForward.startOf('day').toISODate(),
|
||||
endDate: oneWeekForward.endOf('day').toISODate(),
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Utvecklingsamtal',
|
||||
id: 76,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-04',
|
||||
endDate: '2021-02-04',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Vänliga veckan',
|
||||
id: 77,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-08',
|
||||
endDate: '2021-02-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Utvecklingsamtal',
|
||||
id: 79,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-09',
|
||||
endDate: '2021-02-09',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Trygghetsdag',
|
||||
id: 78,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-12',
|
||||
endDate: '2021-02-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT fritids stänger 15:45',
|
||||
id: 80,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-02-25',
|
||||
endDate: '2021-02-25',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Sportlov',
|
||||
id: 81,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-03-01',
|
||||
endDate: '2021-03-05',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Studiedag',
|
||||
id: 82,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-03-22',
|
||||
endDate: '2021-03-22',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT - fritids stänger 15:45',
|
||||
id: 83,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-01',
|
||||
endDate: '2021-04-01',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Långfredag',
|
||||
id: 84,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-02',
|
||||
endDate: '2021-04-02',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Påsklov',
|
||||
id: 85,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-05',
|
||||
endDate: '2021-04-09',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Föräldraråd',
|
||||
id: 86,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-20',
|
||||
endDate: '2021-04-20',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Prao åk 8',
|
||||
id: 97,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-04-26',
|
||||
endDate: '2021-05-12',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Kristi Himmelfärd',
|
||||
id: 87,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-05-13',
|
||||
endDate: '2021-05-13',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'Lov',
|
||||
id: 88,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-05-14',
|
||||
endDate: '2021-05-14',
|
||||
allDay: true,
|
||||
},
|
||||
{
|
||||
title: 'APT Fritids stänger 15:45',
|
||||
id: 90,
|
||||
description: null,
|
||||
location: null,
|
||||
startDate: '2021-05-20',
|
||||
endDate: '2021-05-20',
|
||||
allDay: true,
|
||||
},
|
||||
],
|
||||
schedule: [
|
||||
{
|
||||
title: 'Läxförhör franska',
|
||||
description: 'Läxförhör, glosor samt verben!',
|
||||
location: 'Klassrummet',
|
||||
allDayEvent: false,
|
||||
startDate: twoDaysForward.startOf('day').toISO(),
|
||||
endDate: twoDaysForward.endOf('day').toISO(),
|
||||
oneDayEvent: false
|
||||
} as ScheduleItem
|
||||
],
|
||||
notifications: [
|
||||
{
|
||||
id: 'e1b5bc-597fa8-5511794939-3614e1-615',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: fourDaysAgo.toISO(),
|
||||
dateModified: fourDaysAgo.toISO(),
|
||||
message: 'Ett nytt inlägg i en lärlogg har skapats.',
|
||||
url:
|
||||
'https://www.mitti.se/nyheter/rekorddyr-skolplattform-kostar-258-miljoner-till/lmsao!5381301/',
|
||||
category: 'Lärlogg',
|
||||
messageType: 'avisering',
|
||||
},
|
||||
{
|
||||
id: '7dbc20-bfa1ac-e20171b865-82c1f7-f3c',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-12-01T12:43:00.000Z',
|
||||
message: 'Ett nytt inlägg i en lärlogg har skapats.',
|
||||
url:
|
||||
'https://computersweden.idg.se/2.2683/1.722561/lacka-skolplattformen-datainspektionen',
|
||||
category: 'Lärlogg',
|
||||
messageType: 'avisering',
|
||||
},
|
||||
{
|
||||
id: 'a6829b-ecf912-b71582e8fb-b6dc14-f60',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-11-24T13:34:00.000Z',
|
||||
message: 'Ett nytt inlägg i en lärlogg har skapats.',
|
||||
url: 'https://www.dagensarena.se/redaktionen/en-systemkramare-ger-upp/',
|
||||
category: 'Lärlogg',
|
||||
messageType: 'avisering',
|
||||
},
|
||||
{
|
||||
id: '3cedb4-767d24-8ccd6ac3ac-c05cb7-a3a',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-11-16T13:24:00.000Z',
|
||||
message: 'Ett nytt inlägg i en lärlogg har skapats.',
|
||||
url:
|
||||
'https://www.breakit.se/artikel/27075/skolplattformen-kostade-1-miljard-att-bygga-nu-tvingas-stockholm-bota',
|
||||
category: 'Lärlogg',
|
||||
messageType: 'avisering',
|
||||
},
|
||||
{
|
||||
id: '6ace13-5f99da-d1d50ac7a6-4a6108-d8e',
|
||||
sender: 'Planering och Bedömning',
|
||||
dateCreated: '2020-11-12T13:27:00.000Z',
|
||||
message: 'Ett nytt inlägg i en lärlogg har skapats.',
|
||||
url:
|
||||
'https://www.nyteknik.se/sakerhet/ygeman-om-datalackan-i-skolplattformen-det-ar-upprorande-6968853',
|
||||
category: 'Lärlogg',
|
||||
messageType: 'avisering',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export const user = (): User => ({
|
||||
personalNumber: '195001182046', // Test personal number from Skatteverket
|
||||
firstName: 'Namn',
|
||||
lastName: 'Namnsson',
|
||||
isAuthenticated: true
|
||||
})
|
||||
|
||||
export const calendar = (child: Child): CalendarItem[] =>
|
||||
data[child.id].calendar
|
||||
|
||||
export const schedule = (child: Child): ScheduleItem[] =>
|
||||
data[child.id].schedule
|
||||
|
||||
export const notifications = (child: Child): Notification[] =>
|
||||
data[child.id].notifications
|
|
@ -0,0 +1,14 @@
|
|||
import { DateTime } from "luxon"
|
||||
|
||||
export const getDate = () => DateTime.now()
|
||||
export const oneDayAgo = getDate().minus({days: 1})
|
||||
export const twoDaysAgo = getDate().minus({days: 2})
|
||||
export const fourDaysAgo = getDate().minus({days: 4})
|
||||
export const oneWeekAgo = getDate().minus({weeks: 1})
|
||||
|
||||
export const oneDayForward = getDate().plus({days: 1})
|
||||
export const twoDaysForward = getDate().plus({days: 2})
|
||||
export const fourDaysForward = getDate().plus({days: 4})
|
||||
export const oneWeekForward = getDate().plus({weeks: 1})
|
||||
|
||||
export const week = getDate().weekNumber.toString()
|
|
@ -0,0 +1,8 @@
|
|||
export * from './data'
|
||||
export * from './children'
|
||||
export * from './menu'
|
||||
export * from './classmates'
|
||||
export * from './teachers'
|
||||
export * from './timetable'
|
||||
export * from './schoolContacts'
|
||||
export * from './news'
|
|
@ -0,0 +1,64 @@
|
|||
import { Child, MenuItem } from '@skolplattformen/api'
|
||||
import { DateTime } from 'luxon'
|
||||
import { children } from './children'
|
||||
|
||||
export const menu = (child: Child): MenuItem[] => menuData.get(child.id) ?? []
|
||||
|
||||
const getDate = () => DateTime.now()
|
||||
const week = getDate().weekNumber.toString()
|
||||
|
||||
const [child1, child2] = children()
|
||||
|
||||
const menuData = new Map<string, MenuItem[]>([
|
||||
[
|
||||
child1.id,
|
||||
[
|
||||
{
|
||||
title: 'Måndag - Vecka ' + week,
|
||||
description: 'Kebabgryta ris<br/>Ratatouille med kikärter',
|
||||
},
|
||||
{
|
||||
title: 'Tisdag - Vecka ' + week,
|
||||
description: 'Ost-broccolisås pasta Fusilli',
|
||||
},
|
||||
{
|
||||
title: 'Onsdag - Vecka ' + week,
|
||||
description: 'Köttbullar potatis gräddsås lingon<br/>Falafel',
|
||||
},
|
||||
{
|
||||
title: 'Torsdag - Vecka ' + week,
|
||||
description:
|
||||
'Prinskorv potatis rödbetssallad +<br/>Inlagd och senapssill',
|
||||
},
|
||||
{
|
||||
title: 'Fredag - Vecka ' + week,
|
||||
description:
|
||||
'Avslutning Varmkorv bröd ketchup senap<br/>( F-3 i matsalen från 10:30 )',
|
||||
},
|
||||
],
|
||||
],
|
||||
[child2.id,
|
||||
[
|
||||
{
|
||||
title: "Måndag - Vecka " + week,
|
||||
description: "Thailändsk kycklinggryta med kokosmjölk, rödcurry och jasminris<br/>Thailänsk grönsaksgryta med kokosmjölk, rödcurry och jasminris"
|
||||
},
|
||||
{
|
||||
title: "Tisdag - Vecka " + week,
|
||||
description: "Örtomlett med potatis , medelhavsost och olivtapenad"
|
||||
},
|
||||
{
|
||||
title: "Onsdag - Vecka " + week,
|
||||
description: "Spagetti med rökt kalkon , grädde, dijon och persilja<br/>Spagetti med rostade bönor , grädde , dijon och persilja"
|
||||
},
|
||||
{
|
||||
title: "Torsdag - Vecka " + week,
|
||||
description: "Panerad flundra med dansk remoulad och koktåotatis<br/>morot och linsbiff med danska remoulad och koktpotatis"
|
||||
},
|
||||
{
|
||||
title: "Fredag - Vecka " + week,
|
||||
description: "Texaschili på högrev med picklad rödlök och bulgur<br/>Texaschili på svartabönor picklad rödlök och bulgur"
|
||||
}
|
||||
],
|
||||
]
|
||||
])
|
|
@ -0,0 +1,143 @@
|
|||
import { children } from './children'
|
||||
import { Child, NewsItem } from '@skolplattformen/api'
|
||||
import * as dates from './dates'
|
||||
|
||||
export const news = (child: Child): NewsItem[] => newsData.get(child.id) ?? []
|
||||
|
||||
const [child1, child2] = children()
|
||||
|
||||
const newsData = new Map<string, NewsItem[]>([
|
||||
[child1.id, [
|
||||
{
|
||||
id: 'asdfasdfasdfw',
|
||||
author: 'Vaktmästare Persson',
|
||||
header: 'Brandsläckare!',
|
||||
intro: 'Idag hade vi en incident med en brandsläckare.',
|
||||
body:
|
||||
'## Information om brandsläckarincidenten\n\nHej, idag vid lunchtid utlöste en elev av misstag en pulverbrandsläckare i kapprummet. En del pulver yrde runt i rummet och under saneringen fick eleverna i angränsande klassrum vara i aulan istället för klassrummet.\n\nFlera elever var på plats i hallen när detta inträffade men utrymdes kort därefter. Pulvret är INTE hälsovådligt men kan ge upphov till halsirritation vid inandning.\n\nJag har pratat med berörda elever om det inträffade och uppmanat dem att ta hem kläder och tillhörigheter som fanns i kapprummet eftersom de troligen blivit dammiga. Vi rekommenderar att ni tvättar eller vädrar dessa.',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl:
|
||||
'https://cdn.breakit.se/assets/article/6607f9b923edb6f85aa4417bab43c0f8.jpg?d=980x500',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.twoDaysAgo.toISO(),
|
||||
modified: dates.twoDaysAgo.plus({ hours: 1 }).toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfabbuasdfs',
|
||||
author: 'Ada L.',
|
||||
header: 'Bygg din egen app',
|
||||
intro: 'Denna vecka bygger vi appar!',
|
||||
body:
|
||||
'## Appar med öppen data \n\nDenna vecka har vi förmånen att få besök av några föräldrar som visar hur vi enkelt kan skapa appar som visar information ifrån öppna datakällor.\n\nEn fantastisk möjlighet att lära oss hur digitalisering skapar nya möjligheter i såväl skolan som arbetslivet.',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl:
|
||||
'https://live.staticflickr.com/4063/4369776892_5cd42d27ba.jpg',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.toISO(),
|
||||
modified: dates.oneWeekAgo.toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfasdfasdfs',
|
||||
author: 'Magister Svensson',
|
||||
header: 'Läxor vecka 6.',
|
||||
intro: 'Alla elever måste göra sina läxor!',
|
||||
body:
|
||||
'## Läxor vecka 6 \n\nFöljande läxor är obligatoriska:\n\n- Antikens historia\n- Svenska stormaktstiden\n- Statistik A\n- Flerdimensionell analys, del 1',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl:
|
||||
'https://www.mitti.se/_internal/cimg!0/ejf8efxee735ymm8tm40q3hhkl36sdt.jpeg',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.toISO(),
|
||||
modified: dates.oneWeekAgo.minus({ hours: 3 }).toISO(),
|
||||
},
|
||||
]
|
||||
],
|
||||
|
||||
[child2.id, [
|
||||
{
|
||||
id: 'asdfasdfasdfa',
|
||||
author: 'Rektor Gustavsson',
|
||||
header: 'Välkommen till skolan!',
|
||||
intro:
|
||||
'Hej alla barn och föräldrar och välkomna till Storskolan! Här kommer en del information som kan vara bra att känna till inför första dagen.',
|
||||
body:
|
||||
'## Information till föräldrar \n\nSkolan börjar kl 08.00 och slutar 18.00. Kommer man sent eller blir sjuk så ska det anmälas via Skolplattformen. Se till så att dina barn har ätit frukost. Frukt är nyttigt! \n\n## Information till barn\n\nLek är tillåtet på rasterna men enbart på skolgården. Medtag ej egna leksaker. Tvätta händerna.',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl:
|
||||
'https://timbro.se/app/uploads/2020/10/broman-skolplattformen-1280x752.jpg',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.toISO(),
|
||||
modified: dates.oneWeekAgo.toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfabbuasdfs',
|
||||
author: 'Ada L.',
|
||||
header: 'App, App, App',
|
||||
intro: 'Denna vecka bygger vi appar!',
|
||||
body:
|
||||
'## Appar med öppen data \n\nDenna vecka har vi förmånen att få besök av några föräldrar som visar hur vi enkelt kan skapa appar som visar information ifrån öppna datakällor.\n\nEn fantastisk möjlighet att lära oss hur digitalisering skapar nya möjligheter i såväl skolan som arbetslivet.',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl:
|
||||
'https://live.staticflickr.com/4063/4369776892_5cd42d27ba.jpg',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.fourDaysAgo.toISO(),
|
||||
modified: dates.fourDaysAgo.plus({minutes: 45}).toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfasdfasdfs',
|
||||
author: 'Magister Svensson',
|
||||
header: 'Läxor i veckan',
|
||||
intro: 'Alla elever måste göra sina läxor!',
|
||||
body:
|
||||
'## Läxor vecka 6 \n\nFöljande läxor är obligatoriska:\n\n- Antikens historia\n- Svenska stormaktstiden\n- Statistik A\n- Flerdimensionell analys, del 1',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl:
|
||||
'https://www.mitti.se/_internal/cimg!0/ejf8efxee735ymm8tm40q3hhkl36sdt.jpeg',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.toISO(),
|
||||
modified: dates.oneWeekAgo.toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfasdfasdfd',
|
||||
author: 'Information från Förskoleklass',
|
||||
header: 'Vinteraktiviteter',
|
||||
intro:
|
||||
'Vi kommer efter att förskoleklassen är slut arrangera olika vinteraktiviteter genom fridtidsverksamheten.',
|
||||
body:
|
||||
'## Vänligen ta med hjälm, skridskor eller stjärtlapp.\n\n ![Bild](https://images.unsplash.com/photo-1495377701095-00261b767581?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=988&q=80)\n\n Alla barn måste ha hjälm på sig samt varma kläder. Vi kommer åka i backen bakom skolbyggnaden samt använda isen som spolats vid Mullsjöskolan. Personal kommer finnas på plats samt att vi erbjuda varm dryck, frukt och lek för de barn som ej har hjälm eller lämpligt åkdon.',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl: 'https://unsplash.com/photos/yB_aiAWkm40',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.minus({weeks: 2}).toISO(),
|
||||
modified: dates.oneWeekAgo.minus({weeks: 1}).toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfasdfasdfdsa',
|
||||
author: 'Köket',
|
||||
header: 'Ekologisk vecka i matsalen',
|
||||
intro: 'Ekologiska veckan i matsalen vecka 11',
|
||||
body:
|
||||
'## Vi kommer ha tema jorden i matsalen och servera ekologisk mat från hela världen med tema jorden. Detta för att belysa att man kan använda alla delar av råvaorna. Det kommer erbjudas rätter från alla världsdelar som är producerat för jordens bästa. Smaklig spis hälsar Gunnel i köket med personal.',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl: 'https://unsplash.com/photos/7K17MvT8qBg',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.minus({weeks: 3}).toISO(),
|
||||
modified: dates.oneWeekAgo.minus({days: 2}).toISO(),
|
||||
},
|
||||
{
|
||||
id: 'asdfasdfasdfbvdsa',
|
||||
author: 'Vaktmästaren',
|
||||
header: 'Klotter i korridoren (igen)',
|
||||
intro:
|
||||
'Ännu en gång har vi råka ut för skadegörelse i korridorerna vid åk 5',
|
||||
body:
|
||||
'## Tyvärr har flera elever klottat på skåp och väggar vid åk5 skåpen. Detta är helt oacceptablet beteende och kostar skolan stora belopp att åtgärda. Vi ber alla föräldrar prata med sina barn om klotter samt att det var väldigt grovt spårkbruk. Personalen på skolan kommer att hålla extra uppsikt och vi har även pratat med en del av de inblandade eleverna i denna skadegörelse.\n\nPersonalen har även börjat forska på vad vissa av de skrivna orden betyder och Eva-Britt är förfasad över språkbruket samt vad de innebär. Bernt kommer att påbörja saneringen och återställningen av skadegörelsen samt vakta korridorerna nogrannare för att säkerställa att detta ej kommer ske igen.\n\n Klotter\n\nUPPDATERING: Det som är skrivet om Sara är inte sant! ',
|
||||
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
|
||||
fullImageUrl: 'https://unsplash.com/photos/SkbEZ16VywM',
|
||||
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',
|
||||
published: dates.oneWeekAgo.minus({weeks: 4}).toISO(),
|
||||
modified: dates.oneWeekAgo.minus({weeks: 2}).toISO(),
|
||||
},
|
||||
]
|
||||
]
|
||||
])
|
|
@ -0,0 +1,47 @@
|
|||
import { SchoolContact, Child } from '@skolplattformen/api';
|
||||
import { children } from './children'
|
||||
|
||||
export const schoolContacts = (child: Child): SchoolContact[] => schoolContactData.get(child.id) ?? []
|
||||
|
||||
const [child1,child2] = children()
|
||||
|
||||
const schoolContactData = new Map<string, SchoolContact[]>([
|
||||
[
|
||||
child1.id, [
|
||||
{
|
||||
title: "Expedition",
|
||||
name: null,
|
||||
phone: "508 000 00",
|
||||
email: "",
|
||||
schoolName: "Vallaskolan",
|
||||
className: null,
|
||||
},
|
||||
{
|
||||
title: "Rektor",
|
||||
name: "Alvar Sträng",
|
||||
phone: "08-50800001",
|
||||
email: "alvar.strang@edu.stockholm.se",
|
||||
schoolName: null,
|
||||
className: null,
|
||||
}
|
||||
]],
|
||||
[
|
||||
child2.id, [
|
||||
{
|
||||
title: "Expedition",
|
||||
name: null,
|
||||
phone: "508 000 00",
|
||||
email: "",
|
||||
schoolName: "Vallaskolan",
|
||||
className: null,
|
||||
},
|
||||
{
|
||||
title: "Rektor",
|
||||
name: "Alvar Sträng",
|
||||
phone: "08-50800001",
|
||||
email: "alvar.strang@edu.stockholm.se",
|
||||
schoolName: null,
|
||||
className: null,
|
||||
}
|
||||
]]
|
||||
])
|
|
@ -0,0 +1,81 @@
|
|||
import { Teacher, Child } from '@skolplattformen/api';
|
||||
import { children } from './children'
|
||||
|
||||
export const teachers = (child: Child): Teacher[] => teacherData.get(child.id) ?? []
|
||||
|
||||
const [child1,child2] = children()
|
||||
|
||||
const teacherData = new Map<string, Teacher[]>([
|
||||
[
|
||||
child1.id, [
|
||||
{
|
||||
id: 15662220,
|
||||
firstname: "Cecilia",
|
||||
sisId: null,
|
||||
lastname: "Test",
|
||||
email: "cecilia.test@edu.stockholm.se",
|
||||
phoneWork: null,
|
||||
active: true,
|
||||
status: " S",
|
||||
timeTableAbbreviation: 'CTE',
|
||||
},
|
||||
{
|
||||
id: 15662221,
|
||||
firstname: "Anna",
|
||||
lastname: "Test",
|
||||
sisId: null,
|
||||
email: "anna.test@edu.stockholm.se",
|
||||
phoneWork: '08000000',
|
||||
active: true,
|
||||
status: " GR",
|
||||
timeTableAbbreviation: 'ATE',
|
||||
},
|
||||
{
|
||||
id: 15662221,
|
||||
firstname: "Greta",
|
||||
lastname: "Test",
|
||||
sisId: null,
|
||||
email: null,
|
||||
phoneWork: '08000001',
|
||||
active: true,
|
||||
status: " F",
|
||||
timeTableAbbreviation: 'GTE',
|
||||
},
|
||||
]],
|
||||
[
|
||||
child2.id, [
|
||||
{
|
||||
id: 15662220,
|
||||
firstname: "Cecilia",
|
||||
sisId: null,
|
||||
lastname: "Test",
|
||||
email: "cecilia.test@edu.stockholm.se",
|
||||
phoneWork: null,
|
||||
active: true,
|
||||
status: " S",
|
||||
timeTableAbbreviation: 'CTE',
|
||||
},
|
||||
{
|
||||
id: 15662221,
|
||||
firstname: "Anna",
|
||||
lastname: "Test",
|
||||
sisId: null,
|
||||
email: "anna.test@edu.stockholm.se",
|
||||
phoneWork: '08000000',
|
||||
active: true,
|
||||
status: " GR",
|
||||
timeTableAbbreviation: 'ATE',
|
||||
},
|
||||
{
|
||||
id: 15662221,
|
||||
firstname: "Greta",
|
||||
lastname: "Test",
|
||||
sisId: null,
|
||||
email: null,
|
||||
phoneWork: '08000001',
|
||||
active: true,
|
||||
status: " F",
|
||||
timeTableAbbreviation: 'GTE',
|
||||
},
|
||||
]],
|
||||
])
|
|
@ -0,0 +1,465 @@
|
|||
import { Skola24Child, TimetableEntry } from "@skolplattformen/api"
|
||||
|
||||
|
||||
export const timetable = (child: Skola24Child): TimetableEntry[] => {
|
||||
if (!child.personGuid || !child.unitGuid) return []
|
||||
return [
|
||||
{
|
||||
id: 'N2FjMDc1NjYtZmM2Yy0wZDQyLTY3M2YtZWI5NGNiZDA3ZGU4',
|
||||
code: 'Lunch',
|
||||
name: 'Lunch',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 1,
|
||||
location: 'Ö5',
|
||||
teacher: '',
|
||||
timeEnd: '12:05:00',
|
||||
timeStart: '11:40:00',
|
||||
dateStart: '2021-04-12T11:40:00.000+02:00',
|
||||
dateEnd: '2021-04-12T12:05:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZTQ1NWE0N2EtNzAwOS0wZTAzLTQ1ZDYtNTA1NWI4Y2JhNDYw',
|
||||
code: 'BL',
|
||||
name: 'Bild',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 1,
|
||||
location: '221',
|
||||
teacher: 'CTe',
|
||||
timeEnd: '11:35:00',
|
||||
timeStart: '09:40:00',
|
||||
dateStart: '2021-04-12T09:40:00.000+02:00',
|
||||
dateEnd: '2021-04-12T11:35:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'YjAxODRmY2QtNTJjZS0wMDJlLTYxOGItYmFlNTVlNDgzZmVk',
|
||||
code: 'NO',
|
||||
name: 'Naturorienterande ämnen',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 1,
|
||||
location: '307',
|
||||
teacher: 'TBo',
|
||||
timeEnd: '13:30:00',
|
||||
timeStart: '12:30:00',
|
||||
dateStart: '2021-04-12T12:30:00.000+02:00',
|
||||
dateEnd: '2021-04-12T13:30:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'MWRiZGI1NzgtYWIzNy0wYzMwLTVkMmEtMWFjNWRkMTRmOTdh',
|
||||
code: 'IDH',
|
||||
name: 'Idrott & hälsa',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 1,
|
||||
location: '215',
|
||||
teacher: 'ATe, GTe',
|
||||
timeEnd: '15:45:00',
|
||||
timeStart: '14:40:00',
|
||||
dateStart: '2021-04-12T14:40:00.000+02:00',
|
||||
dateEnd: '2021-04-12T15:45:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'MmZkZTZiMzMtMjdjMS0wZGIzLTUzYWYtZTg0Zjc1NDRlNzQw',
|
||||
code: 'M2FR',
|
||||
name: 'Franska',
|
||||
category: 'Moderna språk, språkval',
|
||||
blockName: '',
|
||||
dayOfWeek: 1,
|
||||
location: '304',
|
||||
teacher: 'CTe,ATe',
|
||||
timeEnd: '14:25:00',
|
||||
timeStart: '13:40:00',
|
||||
dateStart: '2021-04-12T13:40:00.000+02:00',
|
||||
dateEnd: '2021-04-12T14:25:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'MzAxMzU3MWItZGM1Ny0wOGVhLTVkZjUtOGFkMGIyYTY2OTAx',
|
||||
code: 'SO',
|
||||
name: 'Samhällsorienterande ämnen',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 1,
|
||||
location: '303',
|
||||
teacher: 'HRr',
|
||||
timeEnd: '09:25:00',
|
||||
timeStart: '08:15:00',
|
||||
dateStart: '2021-04-12T08:15:00.000+02:00',
|
||||
dateEnd: '2021-04-12T09:25:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NDY3MDY1MmYtOTIzYi0wZmQ0LTVlZGEtNGVhZDRkOTExNTgz',
|
||||
code: 'M2FR',
|
||||
name: 'Franska',
|
||||
category: 'Moderna språk, språkval',
|
||||
blockName: '',
|
||||
dayOfWeek: 2,
|
||||
location: '302,Fjärr asd asdasd asdad aasdds',
|
||||
teacher: 'DNi',
|
||||
timeEnd: '09:50:00',
|
||||
timeStart: '09:05:00',
|
||||
dateStart: '2021-04-13T09:05:00.000+02:00',
|
||||
dateEnd: '2021-04-13T09:50:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NmE4OTU1NmItYzM0ZS0wYTI1LTYzM2QtYzBiN2M4OTVmYTQ3',
|
||||
code: 'EN',
|
||||
name: 'Engelska',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 2,
|
||||
location: 'Fjärr',
|
||||
teacher: 'TPe',
|
||||
timeEnd: '13:15:00',
|
||||
timeStart: '12:30:00',
|
||||
dateStart: '2021-04-13T12:30:00.000+02:00',
|
||||
dateEnd: '2021-04-13T13:15:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NDAxODRjOTctMmE5ZC0wMzdjLTY2NDMtODhlODEzOTQ3YTJh',
|
||||
code: 'Lunch',
|
||||
name: 'Lunch',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 2,
|
||||
location: 'Fjärr',
|
||||
teacher: '',
|
||||
timeEnd: '12:05:00',
|
||||
timeStart: '11:40:00',
|
||||
dateStart: '2021-04-13T11:40:00.000+02:00',
|
||||
dateEnd: '2021-04-13T12:05:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZTc4YTcyZTUtMDc0NS0wNDE0LTVjODctYjY0MzQ2MGM3MDll',
|
||||
code: 'MA',
|
||||
name: 'Matematik',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 2,
|
||||
location: 'Fjärr',
|
||||
teacher: 'CBr',
|
||||
timeEnd: '11:20:00',
|
||||
timeStart: '10:00:00',
|
||||
dateStart: '2021-04-13T10:00:00.000+02:00',
|
||||
dateEnd: '2021-04-13T11:20:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'MjRkMWE4YTItYTk5ZC0wYTFmLTVhMDgtMThiMmNhZDc1ZDUz',
|
||||
code: 'MU',
|
||||
name: 'Musik',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 2,
|
||||
location: 'Fjärr',
|
||||
teacher: 'KBj',
|
||||
timeEnd: '14:15:00',
|
||||
timeStart: '13:30:00',
|
||||
dateStart: '2021-04-13T13:30:00.000+02:00',
|
||||
dateEnd: '2021-04-13T14:15:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NTU4ZTc4ZTctNDQyMy0wMjVkLTRiYzktZGUwYmFmYzk2YTlj',
|
||||
code: 'EN',
|
||||
name: 'Engelska',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '303',
|
||||
teacher: 'TPe',
|
||||
timeEnd: '09:55:00',
|
||||
timeStart: '09:10:00',
|
||||
dateStart: '2021-04-14T09:10:00.000+02:00',
|
||||
dateEnd: '2021-04-14T09:55:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NDUyNjIxODItYzFiOC0wOTFjLTYwODYtZDllZjZjN2QyYzA3',
|
||||
code: 'SV',
|
||||
name: 'Svenska',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '303',
|
||||
teacher: 'JCa',
|
||||
timeEnd: '14:45:00',
|
||||
timeStart: '14:00:00',
|
||||
dateStart: '2021-04-14T14:00:00.000+02:00',
|
||||
dateEnd: '2021-04-14T14:45:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NDdkMGI0ZjItMjkxMC0wYWI1LTQ0YWMtNDY3NTdkZTE2Njg3',
|
||||
code: 'SO',
|
||||
name: 'Engelska',
|
||||
category: 'Samhällsorienterande ämnen',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '303',
|
||||
teacher: 'HRr',
|
||||
timeEnd: '11:00:00',
|
||||
timeStart: '10:05:00',
|
||||
dateStart: '2021-04-14T10:05:00.000+02:00',
|
||||
dateEnd: '2021-04-14T11:00:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZTI2ZDgyNWUtM2ZlOS0wZDVmLTY5NTctNGYzZThjMTMxOTdh',
|
||||
code: 'NO',
|
||||
name: 'Naturorienterande ämnen',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '307',
|
||||
teacher: 'TBo',
|
||||
timeEnd: '13:50:00',
|
||||
timeStart: '12:50:00',
|
||||
dateStart: '2021-04-14T12:50:00.000+02:00',
|
||||
dateEnd: '2021-04-14T13:50:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NzMxNjczNGMtMmZmZi0wM2YzLTU0ZjMtODdjOTAwYzIwNTUw',
|
||||
code: 'Lunch',
|
||||
name: 'Lunch',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: 'Ö5',
|
||||
teacher: '',
|
||||
timeEnd: '12:40:00',
|
||||
timeStart: '12:15:00',
|
||||
dateStart: '2021-04-14T12:15:00.000+02:00',
|
||||
dateEnd: '2021-04-14T12:40:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'MWRkZjhlZTktNTBmMC0wZjNhLTQ1OTgtMWJkOWM3MjI2NWQ4',
|
||||
code: 'SV',
|
||||
name: 'Svenska',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '303',
|
||||
teacher: 'JCa',
|
||||
timeEnd: '12:05:00',
|
||||
timeStart: '11:20:00',
|
||||
dateStart: '2021-04-14T11:20:00.000+02:00',
|
||||
dateEnd: '2021-04-14T12:05:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NzM2Mjc2ZTYtY2JlYy0wOTc1LTU1ZGYtNjMwZjhjZWVjNjgy',
|
||||
code: 'MA',
|
||||
name: 'Matematik',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '307',
|
||||
teacher: 'CBr',
|
||||
timeEnd: '15:45:00',
|
||||
timeStart: '15:00:00',
|
||||
dateStart: '2021-04-14T15:00:00.000+02:00',
|
||||
dateEnd: '2021-04-14T15:45:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'YWNlZmEzZjYtM2EwNC0wYWY3LTU1N2MtMDBlMTA4MDQzMzRl',
|
||||
code: 'MU',
|
||||
name: 'Musik',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 3,
|
||||
location: '504',
|
||||
teacher: 'KBj',
|
||||
timeEnd: '09:00:00',
|
||||
timeStart: '08:15:00',
|
||||
dateStart: '2021-04-14T08:15:00.000+02:00',
|
||||
dateEnd: '2021-04-14T09:00:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NDc4MThmMDYtYmYxYi0wZDBkLTdhNmItZGVjMjY3OWY3MmYz',
|
||||
code: 'IDH',
|
||||
name: 'Idrott & Hälsa',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: 'AKö,CSv,HAl',
|
||||
timeEnd: '15:45:00',
|
||||
timeStart: '14:35:00',
|
||||
dateStart: '2021-04-15T14:35:00.000+02:00',
|
||||
dateEnd: '2021-04-15T15:45:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZjQyZjNkOWItYWMzZi0wYWRhLTQ3YzItNTZiNTJkOTRmY2Iy',
|
||||
code: 'M2FR',
|
||||
name: 'Franska',
|
||||
category: 'Moderna språk, språkval',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: 'DNi',
|
||||
timeEnd: '11:55:00',
|
||||
timeStart: '11:10:00',
|
||||
dateStart: '2021-04-15T11:10:00.000+02:00',
|
||||
dateEnd: '2021-04-15T11:55:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'YzQ2NWZlOWMtYzM3ZC0wYzBlLTQzNTQtODMyYmU3ODcxMDQ3',
|
||||
code: 'MTID',
|
||||
name: 'Mentorstid',
|
||||
category: 'Diverse',
|
||||
comment: 'Arbetslagsråd 6C',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: 'JCa,CBr',
|
||||
timeEnd: '10:00:00',
|
||||
timeStart: '09:15:00',
|
||||
dateStart: '2021-04-15T09:15:00.000+02:00',
|
||||
dateEnd: '2021-04-15T10:00:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'YzMwMGY0YzAtNjhjNi0wYzY0LTU1MjctODg2MWQ4ZTRmZTI2',
|
||||
code: 'MU',
|
||||
name: 'Musik',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: 'KBj',
|
||||
timeEnd: '10:55:00',
|
||||
timeStart: '10:10:00',
|
||||
dateStart: '2021-04-15T10:10:00.000+02:00',
|
||||
dateEnd: '2021-04-15T10:55:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZDNlNTFhMGUtYWFlYy0wOGI0LTVlMGItOTc0MzFiZmIwODcx',
|
||||
code: 'Lunch',
|
||||
name: 'Lunch',
|
||||
category: 'Diverse',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: '',
|
||||
timeEnd: '12:25:00',
|
||||
timeStart: '12:00:00',
|
||||
dateStart: '2021-04-15T12:00:00.000+02:00',
|
||||
dateEnd: '2021-04-15T12:25:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'MDRiZWMyODMtNjEwZC0wZDYwLTRlOWItYTY1MjAwZTc0YTZm',
|
||||
code: 'SO',
|
||||
name: 'Samhällsorienterande ämnen',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: 'HRr',
|
||||
timeEnd: '13:10:00',
|
||||
timeStart: '12:35:00',
|
||||
dateStart: '2021-04-15T12:35:00.000+02:00',
|
||||
dateEnd: '2021-04-15T13:10:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'YTA0ZTA2NTktYTU5MS0wMTFmLTVlYWYtNWM1MTgxNDJlMDcy',
|
||||
code: 'EN',
|
||||
name: 'Engelska',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 4,
|
||||
location: 'Fjärr',
|
||||
teacher: 'TPe',
|
||||
timeEnd: '14:20:00',
|
||||
timeStart: '13:35:00',
|
||||
dateStart: '2021-04-15T13:35:00.000+02:00',
|
||||
dateEnd: '2021-04-15T14:20:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'OGJhN2MxYTYtMDQ4NS0wNWNhLTUwZWEtZDQ5YzQyMzFhYzc5',
|
||||
code: 'Lunch',
|
||||
name: 'Lunch',
|
||||
category: 'Diverse',
|
||||
blockName: '',
|
||||
dayOfWeek: 5,
|
||||
location: 'Ö5',
|
||||
teacher: '',
|
||||
timeEnd: '12:05:00',
|
||||
timeStart: '11:40:00',
|
||||
dateStart: '2021-04-16T11:40:00.000+02:00',
|
||||
dateEnd: '2021-04-16T12:05:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZmUwMGEwM2QtNTExMy0wODliLTY1ZGEtODM0YmRjNjc1NDIw',
|
||||
code: 'MA',
|
||||
name: 'Matematik',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 5,
|
||||
location: '303',
|
||||
teacher: 'CBr',
|
||||
timeEnd: '14:00:00',
|
||||
timeStart: '13:15:00',
|
||||
dateStart: '2021-04-16T13:15:00.000+02:00',
|
||||
dateEnd: '2021-04-16T14:00:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'Y2IwYjYzZDEtODAxYi0wMTNjLTRjNDMtMDFlODgzMmY4MWEy',
|
||||
code: 'MU',
|
||||
name: 'Musik',
|
||||
category: '',
|
||||
comment: 'a)',
|
||||
blockName: '',
|
||||
dayOfWeek: 5,
|
||||
location: '510',
|
||||
teacher: 'KBj',
|
||||
timeEnd: '13:05:00',
|
||||
timeStart: '12:20:00',
|
||||
dateStart: '2021-04-16T12:20:00.000+02:00',
|
||||
dateEnd: '2021-04-16T13:05:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'N2JkMGFiOTYtMjI5OC0wMjZiLTc3OGEtN2JkN2Q4MDZkNTEy',
|
||||
code: 'SL',
|
||||
name: 'Slöjd',
|
||||
category: '',
|
||||
comment: 'tmtx)',
|
||||
blockName: '',
|
||||
dayOfWeek: 5,
|
||||
location: '860',
|
||||
teacher: 'EAl',
|
||||
timeEnd: '15:10:00',
|
||||
timeStart: '14:10:00',
|
||||
dateStart: '2021-04-16T14:10:00.000+02:00',
|
||||
dateEnd: '2021-04-16T15:10:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'NzkxMjE3MDctMWExNS0wN2RmLTQwMzQtNTEyZTczZjQyZTUw',
|
||||
code: 'SV',
|
||||
name: 'Svenska',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 5,
|
||||
location: '303',
|
||||
teacher: 'JCa',
|
||||
timeEnd: '10:35:00',
|
||||
timeStart: '09:20:00',
|
||||
dateStart: '2021-04-16T09:20:00.000+02:00',
|
||||
dateEnd: '2021-04-16T10:35:00.000+02:00',
|
||||
},
|
||||
{
|
||||
id: 'ZTU1ZDQxNzQtN2Q3Yy0wMDMxLTY2ZmYtZmIyNGM5MjM3ZTRj',
|
||||
code: 'MA',
|
||||
name: 'Matematik',
|
||||
category: '',
|
||||
blockName: '',
|
||||
dayOfWeek: 5,
|
||||
location: '303',
|
||||
teacher: 'CBr',
|
||||
timeEnd: '11:35:00',
|
||||
timeStart: '10:40:00',
|
||||
dateStart: '2021-04-16T10:40:00.000+02:00',
|
||||
dateEnd: '2021-04-16T11:35:00.000+02:00',
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
|
|||
import { loginStatus } from './routes';
|
||||
import { AuthTicket, Fetcher, LoginStatusChecker } from '@skolplattformen/api';
|
||||
|
||||
export class Checker extends EventEmitter {
|
||||
export class Checker extends EventEmitter implements LoginStatusChecker {
|
||||
public token: string;
|
||||
|
||||
private fetcher: Fetcher;
|
||||
|
@ -41,3 +41,10 @@ export const checkStatus = (
|
|||
fetch: Fetcher,
|
||||
ticket: AuthTicket
|
||||
): LoginStatusChecker => new Checker(fetch, ticket)
|
||||
|
||||
export class DummyStatusChecker extends EventEmitter implements LoginStatusChecker {
|
||||
token = ""
|
||||
async cancel(): Promise<void> {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { EtjanstResponse } from '../'
|
||||
import { schoolContacts } from '../schoolContacts'
|
||||
|
||||
let response: EtjanstResponse
|
||||
|
||||
beforeEach(() => {
|
||||
response = {
|
||||
"Success": true,
|
||||
"Error": null,
|
||||
"Data": [
|
||||
{
|
||||
"Title": "Expedition",
|
||||
"Name": null,
|
||||
"Phone": "508 000 00",
|
||||
"Email": "",
|
||||
"SchoolName": "Påhittade skolan",
|
||||
"ClassName": null
|
||||
},
|
||||
{
|
||||
"Title": "Rektor",
|
||||
"Name": "Andersson, Anna Bella Cecilia",
|
||||
"Phone": "08-508 000 00",
|
||||
"Email": "anna.anderssonn@edu.stockholm.se",
|
||||
"SchoolName": null,
|
||||
"ClassName": null
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
it('parses teachers correctly', () => {
|
||||
expect(schoolContacts(response)).toEqual([
|
||||
{
|
||||
title: 'Expedition',
|
||||
name: null,
|
||||
phone: '508 000 00',
|
||||
email: '',
|
||||
schoolName: 'Påhittade skolan',
|
||||
className: null
|
||||
},
|
||||
{
|
||||
title: 'Rektor',
|
||||
name: 'Andersson, Anna Bella Cecilia',
|
||||
phone: '08-508 000 00',
|
||||
email: 'anna.anderssonn@edu.stockholm.se',
|
||||
schoolName: null,
|
||||
className: null
|
||||
}
|
||||
])
|
||||
})
|
|
@ -0,0 +1,68 @@
|
|||
import { EtjanstResponse } from '../'
|
||||
import { teachers } from '../teachers'
|
||||
|
||||
let response: EtjanstResponse
|
||||
|
||||
beforeEach(() => {
|
||||
response = {
|
||||
"Success": true,
|
||||
"Error": null,
|
||||
"Data": [
|
||||
{
|
||||
"ID": 156735,
|
||||
"BATCH": "GR",
|
||||
"SIS_ID": "F154239A-EA4A-4C6C-A112-0B9581132E3D",
|
||||
"USERNAME": "anna.andersson",
|
||||
"SCHOOL_SIS_ID": "DE2E1293-0F40-4B91-9D91-1E99355DC257",
|
||||
"EMAILADDRESS": null,
|
||||
"STATUS": " GR",
|
||||
"ERRORCODE": 0,
|
||||
"FIRSTNAME": "Anna",
|
||||
"LASTNAME": "Andersson",
|
||||
"ACTIVE": true,
|
||||
"TELWORK": "08 508 0000000"
|
||||
},
|
||||
{
|
||||
"ID": 156690,
|
||||
"BATCH": "GR",
|
||||
"SIS_ID": "9EC59FCA-80AD-4774-AABD-427040207E33",
|
||||
"USERNAME": "gunnar.grymm",
|
||||
"SCHOOL_SIS_ID": "DE2E1293-0F40-4B91-9D91-1E99355DC257",
|
||||
"EMAILADDRESS": "gunnar.grymm@edu.stockholm.se",
|
||||
"STATUS": " F",
|
||||
"ERRORCODE": 0,
|
||||
"FIRSTNAME": "Gunnar",
|
||||
"LASTNAME": "Grymm",
|
||||
"ACTIVE": true,
|
||||
"TELWORK": null
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
it('parses teachers correctly', () => {
|
||||
expect(teachers(response)).toEqual([
|
||||
{
|
||||
id: 156735,
|
||||
sisId: 'F154239A-EA4A-4C6C-A112-0B9581132E3D',
|
||||
firstname: 'Anna',
|
||||
lastname: 'Andersson',
|
||||
email: null,
|
||||
phoneWork: '08 508 0000000',
|
||||
active: true,
|
||||
status: ' GR',
|
||||
timeTableAbbreviation: 'AAN'
|
||||
},
|
||||
{
|
||||
id: 156690,
|
||||
sisId: '9EC59FCA-80AD-4774-AABD-427040207E33',
|
||||
firstname: 'Gunnar',
|
||||
lastname: 'Grymm',
|
||||
email: 'gunnar.grymm@edu.stockholm.se',
|
||||
phoneWork: null,
|
||||
active: true,
|
||||
status: ' F',
|
||||
timeTableAbbreviation: 'GGR'
|
||||
},
|
||||
])
|
||||
})
|
|
@ -6,5 +6,7 @@ export * from './menu'
|
|||
export * from './news'
|
||||
export * from './notifications'
|
||||
export * from './schedule'
|
||||
export * from './schoolContacts'
|
||||
export * from './teachers'
|
||||
export * from './timetable'
|
||||
export * from './user'
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { etjanst } from './etjanst'
|
||||
import { SchoolContact } from '@skolplattformen/api'
|
||||
|
||||
export const schoolContact = ({
|
||||
title,
|
||||
name,
|
||||
phone,
|
||||
email,
|
||||
schoolName,
|
||||
className,
|
||||
}: any): SchoolContact => ({
|
||||
title,
|
||||
name,
|
||||
phone,
|
||||
email,
|
||||
schoolName,
|
||||
className,
|
||||
})
|
||||
|
||||
|
||||
export const schoolContacts = (data: any): SchoolContact[] =>
|
||||
etjanst(data).map(schoolContact)
|
|
@ -0,0 +1,29 @@
|
|||
import { etjanst } from './etjanst'
|
||||
import { Teacher } from '@skolplattformen/api'
|
||||
|
||||
const abbreviate = (firstname?: string, lastname?: string): string =>
|
||||
`${firstname?.substr(0,1)}${lastname?.substr(0,2)}`.toUpperCase()
|
||||
|
||||
export const teacher = ({
|
||||
id,
|
||||
sisId,
|
||||
firstname,
|
||||
lastname,
|
||||
emailaddress,
|
||||
telwork,
|
||||
active,
|
||||
status,
|
||||
}: any): Teacher => ({
|
||||
id,
|
||||
sisId,
|
||||
firstname,
|
||||
lastname,
|
||||
email: emailaddress,
|
||||
phoneWork: telwork,
|
||||
active,
|
||||
status,
|
||||
timeTableAbbreviation: abbreviate(firstname, lastname)
|
||||
})
|
||||
|
||||
export const teachers = (data: any): Teacher[] =>
|
||||
etjanst(data).map(teacher)
|
|
@ -84,6 +84,11 @@ export const timetable = (
|
|||
if (response.error) {
|
||||
throw new Error(response.error)
|
||||
}
|
||||
|
||||
if(!response.data.lessonInfo){
|
||||
throw new Error("Empty lessonInfo received")
|
||||
}
|
||||
|
||||
return response.data.lessonInfo.map((entry) =>
|
||||
timetableEntry(entry, year, week, lang)
|
||||
)
|
||||
|
|
|
@ -20,6 +20,12 @@ export const calendar = (childId: string) =>
|
|||
export const classmates = (childId: string) =>
|
||||
`${urlLoggedIn}/contacts/GetStudentsByClass?studentId=${childId}`
|
||||
|
||||
export const teachers = (childId: string, schoolForm: string) =>
|
||||
`${urlLoggedIn}/contacts/GetTeachersByStudent?studentId=${childId}&schoolForm=${schoolForm}`
|
||||
|
||||
export const schoolContacts = (childId: string, schoolId: string) =>
|
||||
`${urlLoggedIn}/contacts/GetSchoolContacts?schoolId=${schoolId}&studentId=${childId}&schoolForm=Klasslista`
|
||||
|
||||
export const user =
|
||||
'https://etjanst.stockholm.se/vardnadshavare/base/getuserdata'
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import {
|
|||
EtjanstChild,
|
||||
TimetableEntry,
|
||||
ScheduleItem,
|
||||
SchoolContact,
|
||||
Teacher
|
||||
} from './types'
|
||||
|
||||
export interface Api extends EventEmitter {
|
||||
|
@ -21,6 +23,7 @@ export interface Api extends EventEmitter {
|
|||
getPersonalNumber(): string | undefined
|
||||
login(personalNumber?: string): Promise<LoginStatusChecker>
|
||||
setSessionCookie(sessionCookie: string): Promise<void>
|
||||
getSessionHeaders(url: string): Promise<{ [index: string]: string }>
|
||||
getUser(): Promise<User>
|
||||
getChildren(): Promise<EtjanstChild[]>
|
||||
getCalendar(child: EtjanstChild): Promise<CalendarItem[]>
|
||||
|
@ -29,7 +32,9 @@ export interface Api extends EventEmitter {
|
|||
getNewsDetails(child: EtjanstChild, item: NewsItem): Promise<any>
|
||||
getMenu(child: EtjanstChild): Promise<MenuItem[]>
|
||||
getNotifications(child: EtjanstChild): Promise<Notification[]>
|
||||
getTeachers(child: EtjanstChild): Promise<Teacher[]>
|
||||
getSchedule(child: EtjanstChild, from: DateTime, to: DateTime): Promise<ScheduleItem[]>
|
||||
getSchoolContacts(child: EtjanstChild): Promise<SchoolContact[]>
|
||||
getSkola24Children(): Promise<Skola24Child[]>
|
||||
getTimetable(child: Skola24Child, week: number, year: number, lang: Language): Promise<TimetableEntry[]>
|
||||
registerAbscense(child: EtjanstChild, startDate: DateTime, endDate: DateTime): Promise<void>
|
||||
|
|
|
@ -214,3 +214,24 @@ export interface TimetableEntry extends Subject {
|
|||
dateStart: string
|
||||
dateEnd: string
|
||||
}
|
||||
|
||||
export interface Teacher {
|
||||
id: number
|
||||
sisId: string
|
||||
firstname: string
|
||||
lastname: string
|
||||
email?: string
|
||||
phoneWork?: string
|
||||
active: boolean
|
||||
status: string
|
||||
timeTableAbbreviation: string
|
||||
}
|
||||
|
||||
export interface SchoolContact {
|
||||
title?: string
|
||||
name?: string
|
||||
phone?: string
|
||||
email?: string
|
||||
schoolName: string
|
||||
className: string
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ test.each([
|
|||
['15 oktober 2020 11:34', '2020-10-15T09:34:00.000Z'],
|
||||
['2020-12-18T15:59:46.34', '2020-12-18T14:59:46.340Z'],
|
||||
['2020-12-18T15:59:46.340Z', '2020-12-18T15:59:46.340Z'],
|
||||
['/Date(1637935089877)/', '2021-11-26T13:58:09.877Z'],
|
||||
['This is an invalid date', undefined],
|
||||
])('handles date parsing of %s', (input, expected) => {
|
||||
expect(parseDate(input)).toEqual(expected)
|
||||
|
|
|
@ -18,7 +18,7 @@ In order to use api hooks, you must wrap your app in an ApiProvider
|
|||
```javascript
|
||||
import React from 'react'
|
||||
import { ApiProvider } from '@skolplattformen/hooks'
|
||||
import init from '@skolplattformen/api-skolplattformen'
|
||||
import init from '@skolplattformen/api-skolplattformet'
|
||||
import { CookieManager } from '@react-native-cookies/cookies'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { RootComponent } from './components/root'
|
||||
|
|
|
@ -22,6 +22,8 @@ const createApi = () => ({
|
|||
getNewsDetails: jest.fn(),
|
||||
getNotifications: jest.fn(),
|
||||
getSchedule: jest.fn(),
|
||||
getSchoolContacts: jest.fn(),
|
||||
getTeachers: jest.fn(),
|
||||
getTimetable: jest.fn(),
|
||||
getUser: jest.fn(),
|
||||
})
|
||||
|
|
|
@ -9,7 +9,9 @@ import {
|
|||
NewsItem,
|
||||
Notification,
|
||||
ScheduleItem,
|
||||
SchoolContact,
|
||||
Skola24Child,
|
||||
Teacher,
|
||||
TimetableEntry,
|
||||
User,
|
||||
} from '@skolplattformen/api'
|
||||
|
@ -107,7 +109,7 @@ const hook = <T>(
|
|||
|
||||
if (newState.error) {
|
||||
const description = `Error getting ${entityName} from API`
|
||||
reporter.error(newState.error, description)
|
||||
reporter.error && reporter.error(newState.error, description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,8 +203,26 @@ export const useSchedule = (child: Child, from: string, to: string) =>
|
|||
api.getSchedule(child, DateTime.fromISO(from), DateTime.fromISO(to))
|
||||
)
|
||||
|
||||
export const useSchoolContacts = (child: Child) =>
|
||||
hook<SchoolContact[]>(
|
||||
'SCHOOL_CONTACTS',
|
||||
`schoolContacts_${child.id}`,
|
||||
[],
|
||||
(s) => s.schoolContacts,
|
||||
(api) => () => api.getSchoolContacts(child)
|
||||
)
|
||||
|
||||
export const useTeachers = (child: Child) =>
|
||||
hook<Teacher[]>(
|
||||
'TEACHERS',
|
||||
`teachers_${child.id}`,
|
||||
[],
|
||||
(s) => s.teachers,
|
||||
(api) => () => api.getTeachers(child)
|
||||
)
|
||||
|
||||
export const useTimetable = (
|
||||
child: Skola24Child,
|
||||
child: Child,
|
||||
week: number,
|
||||
year: number,
|
||||
lang: Language
|
||||
|
@ -212,9 +232,31 @@ export const useTimetable = (
|
|||
`timetable_${child.personGuid}_${week}_${year}_${lang}`,
|
||||
[],
|
||||
(s) => s.timetable,
|
||||
(api) => () => api.getTimetable(child, week, year, lang)
|
||||
(api) => async () => {
|
||||
const tt = await api.getTimetable(child, week, year, lang)
|
||||
const ts = await api.getTeachers(child)
|
||||
tt.forEach((element) => {
|
||||
element.teacher = replaceTeacherInitials(element.teacher, ts)
|
||||
})
|
||||
return tt
|
||||
}
|
||||
)
|
||||
|
||||
const replaceTeacherInitials = (
|
||||
initials: string,
|
||||
teachers: Teacher[]
|
||||
): string => {
|
||||
if (!initials || teachers?.length == 0) return initials
|
||||
const arr = initials.split(',') || [initials]
|
||||
const arr2 = arr.map((element) => {
|
||||
const t = teachers.find(
|
||||
(t) => t.timeTableAbbreviation === element.trim().toUpperCase()
|
||||
)
|
||||
return t ? `${t.firstname} ${t.lastname}` : element
|
||||
})
|
||||
return arr2.join(', ')
|
||||
}
|
||||
|
||||
export const useUser = () =>
|
||||
hook<User>(
|
||||
'USER',
|
||||
|
|
|
@ -6,7 +6,9 @@ import {
|
|||
NewsItem,
|
||||
Notification,
|
||||
ScheduleItem,
|
||||
SchoolContact,
|
||||
Skola24Child,
|
||||
Teacher,
|
||||
TimetableEntry,
|
||||
User,
|
||||
} from '@skolplattformen/api'
|
||||
|
@ -77,3 +79,5 @@ export const newsDetails = createReducer<NewsItem[]>('NEWS_DETAILS')
|
|||
export const notifications = createReducer<Notification[]>('NOTIFICATIONS')
|
||||
export const schedule = createReducer<ScheduleItem[]>('SCHEDULE')
|
||||
export const timetable = createReducer<TimetableEntry[]>('TIMETABLE')
|
||||
export const teachers = createReducer<Teacher[]>('TEACHERS')
|
||||
export const schoolContacts = createReducer<SchoolContact[]>('SCHOOL_CONTACTS')
|
||||
|
|
|
@ -9,7 +9,9 @@ import {
|
|||
newsDetails,
|
||||
notifications,
|
||||
schedule,
|
||||
schoolContacts,
|
||||
skola24Children,
|
||||
teachers,
|
||||
timetable,
|
||||
user,
|
||||
} from './reducers'
|
||||
|
@ -23,7 +25,9 @@ const appReducer = combineReducers({
|
|||
newsDetails,
|
||||
notifications,
|
||||
schedule,
|
||||
schoolContacts,
|
||||
skola24Children,
|
||||
teachers,
|
||||
timetable,
|
||||
user,
|
||||
})
|
||||
|
|
|
@ -7,7 +7,9 @@ import {
|
|||
NewsItem,
|
||||
Notification,
|
||||
ScheduleItem,
|
||||
SchoolContact,
|
||||
Skola24Child,
|
||||
Teacher,
|
||||
TimetableEntry,
|
||||
User,
|
||||
} from '@skolplattformen/api'
|
||||
|
@ -64,6 +66,8 @@ export type EntityName =
|
|||
| 'NEWS_DETAILS'
|
||||
| 'NOTIFICATIONS'
|
||||
| 'SCHEDULE'
|
||||
| 'SCHOOL_CONTACTS'
|
||||
| 'TEACHERS'
|
||||
| 'TIMETABLE'
|
||||
| 'ALL'
|
||||
export interface EntityAction<T> extends Action<EntityActionType> {
|
||||
|
@ -88,6 +92,8 @@ export interface EntityStoreRootState {
|
|||
newsDetails: EntityMap<NewsItem>
|
||||
notifications: EntityMap<Notification[]>
|
||||
schedule: EntityMap<ScheduleItem[]>
|
||||
schoolContacts: EntityMap<SchoolContact[]>
|
||||
teachers: EntityMap<Teacher[]>
|
||||
timetable: EntityMap<TimetableEntry[]>
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "skolplattformen",
|
||||
"version": "2.3.2",
|
||||
"version": "2.10.2",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "nx start",
|
||||
|
|
Loading…
Reference in New Issue