diff --git a/packages/api/lib/backend.js b/packages/api/lib/backend.js
index 71337d33e..60251864a 100644
--- a/packages/api/lib/backend.js
+++ b/packages/api/lib/backend.js
@@ -1,6 +1,6 @@
const moment = require('moment')
const h2m = require('h2m')
-const {htmlDecode} = require('js-htmlencode')
+const { htmlDecode } = require('js-htmlencode')
const urls = require('./urls')
const { fetchJson, fetchText, fetchRaw } = require('./fetch')
@@ -16,7 +16,7 @@ const login = async (socialSecurityNumber) => {
return token
}
-const waitForToken = async ({order}, tries = 60) => {
+const waitForToken = async ({ order }, tries = 60) => {
if (!tries) return Promise.reject('Timeout')
const status = await fetchText(urls.checkStatus(order))
if (status === 'OK') {
@@ -25,18 +25,18 @@ const waitForToken = async ({order}, tries = 60) => {
} else {
await pause(1000)
console.log('retry', tries)
- return await waitForToken({order}, tries--)
+ return await waitForToken({ order }, tries--)
}
}
const getChildren = async (cookie) => {
const children = await fetchJson(urls.children, cookie)
return children
- .map(({name, id, sdsId, status, schoolId}) =>
- ({name, id, sdsId, status, schoolId}))
+ .map(({ name, id, sdsId, status, schoolId }) =>
+ ({ name, id, sdsId, status, schoolId }))
}
-const getNews = async(childId, cookie) => {
+const getNews = async (childId, cookie) => {
const news = await fetchJson(urls.news(childId), cookie)
return news
.newsItems
@@ -60,7 +60,7 @@ const getNews = async(childId, cookie) => {
const getCalendar = async (childId, cookie) => {
const url = urls.calendar(childId)
const calendar = await fetchJson(url, cookie)
-
+
return calendar
.map(({
title,
@@ -84,7 +84,7 @@ const getCalendar = async (childId, cookie) => {
const getNotifications = async (childId, cookie) => {
const url = urls.notifications(childId)
const notifications = await fetchJson(url, cookie)
-
+
return notifications
.map(({
notificationMessage: {
@@ -124,7 +124,7 @@ const getSchedule = async (childId, cookie) => {
const to = moment().add(7, 'days').format('YYYY-MM-DD')
const url = urls.schedule(childId, from, to)
const schedule = await fetchJson(url, cookie)
-
+
return schedule
.map(({
title,
@@ -150,7 +150,7 @@ const getSchedule = async (childId, cookie) => {
const getClassmates = async (childId, cookie) => {
const url = urls.classmates(childId)
const classmates = await fetchJson(url, cookie)
-
+
return classmates
.map(({
sisId,
@@ -191,10 +191,10 @@ const getChildById = async (childId, cookie) => {
menu,
schedule
] = [
- await getNews(childId, cookie),
- await getCalendar(childId, cookie),
- await getNotifications(child.sdsId, cookie),
- await getMenu(child.id, cookie),
+ await getNews(childId, cookie),
+ await getCalendar(childId, cookie),
+ await getNotifications(child.sdsId, cookie),
+ await getMenu(child.id, cookie),
await getSchedule(child.id, cookie)
]
@@ -220,4 +220,4 @@ module.exports = {
getSchedule,
getClassmates,
download
-}
\ No newline at end of file
+}
diff --git a/packages/app/components/children.component.js b/packages/app/components/children.component.js
index 4ec2852d7..e080aac4b 100644
--- a/packages/app/components/children.component.js
+++ b/packages/app/components/children.component.js
@@ -1,11 +1,11 @@
-import React, {useState, useMemo, useCallback, useEffect } from 'react'
-import { StyleSheet, View, Image } from 'react-native'
-import { SafeAreaView } from 'react-native'
+import React, { useEffect } from 'react'
+import { StyleSheet, View, Image, SafeAreaView } from 'react-native'
+
import moment from 'moment'
import { Divider, Button, Icon, Layout, Text, TopNavigation, TopNavigationAction, List, Card, Avatar, Spinner } from '@ui-kitten/components'
// import children from '../output.json'
-import {useAsyncStorage} from 'use-async-storage'
-import {api, loadChildrenDetails} from '../lib/backend'
+import { useAsyncStorage } from 'use-async-storage'
+import { api, fillChild } from '../lib/backend'
const colors = ['primary', 'success', 'info', 'warning', 'danger']
@@ -25,38 +25,41 @@ const PeopleIcon = (style) => (
)
-export const Children = ({navigation}) => {
+export const Children = ({ navigation }) => {
const [children, setChildren] = useAsyncStorage('@children', [])
-
+ const [cookie] = useAsyncStorage('@cookie')
useEffect(() => {
const load = async () => {
try {
- const childrenList = children?.length || await api.getChildren()
+ const childrenList = (children?.length && children) || await api.getChildren()
if (!childrenList?.length) {
- console.log('no children found')
- return navigation.navigate('Login', {error: 'Hittar inga barn med det personnumret'})
+ console.log('no children found', await api.getChildren())
+ return navigation.navigate('Login', { error: 'Hittar inga barn för det personnumret' })
}
- // Update the list with all details we get the most often updated info first
- const fullChildren = await loadChildrenDetails(childrenList, {calendar: true, schedule: true, news: true, menu:true, notifications: true, classmates: true})
- setChildren(fullChildren)
-
+ childrenList.forEach(async (child, i) => {
+ let result
+ let updatedChild // keep a reference to the latest updated information so we don't patch an old object
+ const iter = fillChild(child)
+ while (!result?.done) {
+ result = await iter.next() // get updated values for every updated property
+ if (result.done) break
+ const updated = await result.value
+ childrenList[i] = updatedChild = { ...updatedChild, ...updated }
+ await setChildren(childrenList) // update after each new information we get. Might be too much?
+ }
+ })
} catch (err) {
console.log('err', err)
- navigation.navigate('Login', {error: 'Fel uppstod, försök igen'})
+ navigation.navigate('Login', { error: 'Fel uppstod, försök igen' })
}
}
- if (api.isLoggedIn) load()
- }, [api.isLoggedIn])
-
- return
+ if (cookie) load()
+ }, [cookie])
+ return
}
-
-export const ChildrenView = ({ navigation, children, eva }) => {
-
-
-
+export const ChildrenView = ({ navigation, childList, eva }) => {
const abbrevations = {
G: 'Gymnasiet', // ? i'm guessing here
GR: 'Grundskolan',
@@ -67,7 +70,7 @@ export const ChildrenView = ({ navigation, children, eva }) => {
}
const navigateChild = (child, color) => {
- navigation.navigate('Child', {child, color})
+ navigation.navigate('Child', { child, color })
}
const BackAction = () => (
@@ -75,11 +78,11 @@ export const ChildrenView = ({ navigation, children, eva }) => {
)
const Header = (props, info, i) => (
-
-
-
+
+
+
-
+
{info.item.name?.split('(')[0]}
@@ -96,21 +99,24 @@ export const ChildrenView = ({ navigation, children, eva }) => {
style={styles.iconButton}
status='control'
size='small'
- accessoryLeft={NotificationIcon}>
+ accessoryLeft={NotificationIcon}
+ >
{`${(info.item.news || []).length}`} nyheter
@@ -118,41 +124,48 @@ export const ChildrenView = ({ navigation, children, eva }) => {
const renderItem = (info) => {
const color = colors[info.index % colors.length]
- return Header(headerProps, info, info.index)}
- footer={footerProps => Footer(footerProps, info)}
- onPress={() => navigateChild(info.item, color)}>
-
- {([...info.item.calendar, ...info.item.schedule].filter(a => moment(a.startDate, 'YYYY-MM-DD hh:mm').isSame('day'))).map((calendarItem, i) =>
-
- {`${calendarItem.title}`}
-
- )}
-
+ return (
+ Header(headerProps, info, info.index)}
+ footer={footerProps => Footer(footerProps, info)}
+ onPress={() => navigateChild(info.item, color)}
+ >
+
+ {([...info.item.calendar ?? [], ...info.item.schedule ?? []].filter(a => moment(a.startDate, 'YYYY-MM-DD hh:mm').isSame('day'))).map((calendarItem, i) =>
+
+ {`${calendarItem.title}`}
+
+ )}
+
+ )
}
return (
-
-
-
+
+
+
- {children?.length ?
+ {
+ childList?.length
+ ?
+ style={styles.container}
+ contentContainerStyle={styles.contentContainer}
+ data={childList}
+ renderItem={renderItem}
+ />
:
-
-
-
- Laddar...
-
- }
+
+
+
+ Laddar...
+
+
+ }
diff --git a/packages/app/components/classmates.component.js b/packages/app/components/classmates.component.js
index ae6fe09e8..0fdcf31da 100644
--- a/packages/app/components/classmates.component.js
+++ b/packages/app/components/classmates.component.js
@@ -1,20 +1,21 @@
-import React from 'react';
-import { StyleSheet } from 'react-native';
-import { Divider, List, ListItem, Icon, Text, Button} from '@ui-kitten/components';
-import { ContactMenu } from './contactMenu.component';
+import React from 'react'
+import { StyleSheet } from 'react-native'
+import { Divider, List, ListItem, Icon } from '@ui-kitten/components'
+import { ContactMenu } from './contactMenu.component'
-export const Classmates = ({classmates}) => {
-
- const renderItemIcon = (props) =>
+export const Classmates = ({ classmates }) => {
+ const renderItemIcon = (props) =>
+ const [selected, setSelected] = React.useState()
const renderItem = ({ item }) => (
setSelected(item)}
description={item.guardians.map(guardian => `${guardian.firstname} ${guardian.lastname}`).join(', ')}
accessoryLeft={renderItemIcon}
- accessoryRight={(props) => ContactMenu({...props, contact: item})}
+ accessoryRight={(props) => ContactMenu({ ...props, contact: item, selected: item === selected, setSelected })}
/>
- );
+ )
return (
{
ItemSeparatorComponent={Divider}
renderItem={renderItem}
/>
- );
-};
+ )
+}
const styles = StyleSheet.create({
container: {
- width: "100%",
- },
-});
\ No newline at end of file
+ width: '100%'
+ }
+})
diff --git a/packages/app/components/contactMenu.component.js b/packages/app/components/contactMenu.component.js
index 8163ae650..5261879bc 100644
--- a/packages/app/components/contactMenu.component.js
+++ b/packages/app/components/contactMenu.component.js
@@ -1,38 +1,46 @@
-import React from 'react';
-import { StyleSheet } from 'react-native';
-import { Button, Icon, Layout, MenuItem, MenuGroup, OverflowMenu, Text, Divider } from '@ui-kitten/components';
-import {Linking} from 'react-native'
+import React from 'react'
+import { StyleSheet, Linking } from 'react-native'
+import { Button, Icon, MenuItem, MenuGroup, OverflowMenu } from '@ui-kitten/components'
+export const ContactMenu = ({ contact, selected, setSelected }) => {
+ const [visible, setVisible] = React.useState(selected)
-export const ContactMenu = ({contact}) => {
-
- const [visible, setVisible] = React.useState(false);
- const [selectedTitle, setSelectedTitle] = React.useState('No items selected');
-
- const contactIcon = (props) =>
+ const contactIcon = (props) =>
const renderToggleButton = () => (
-
- );
+
+
+ }
+ setVisible(false)}>
-
- {hasBankId ? Öppnar BankID. Växla tillbaka hit sen. : Väntar på BankID...}
-
- setVisible(false)}
+ >
+
+ {hasBankId ? Öppnar BankID. Växla tillbaka hit sen. : Väntar på BankID...}
+
+ setVisible(false)}>
+ onPress={() => setVisible(false)}
+ >
Avbryt
@@ -167,12 +176,12 @@ export const Login = ({ navigation, route }) => {
const styles = StyleSheet.create({
container: {
- minHeight: 192,
+ minHeight: 192
},
modal: {
- width: "80%"
+ width: '80%'
},
backdrop: {
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
- },
-})
\ No newline at end of file
+ backgroundColor: 'rgba(0, 0, 0, 0.5)'
+ }
+})
diff --git a/packages/app/components/newsItem.component.js b/packages/app/components/newsItem.component.js
index 59fa18390..46e2227dc 100644
--- a/packages/app/components/newsItem.component.js
+++ b/packages/app/components/newsItem.component.js
@@ -23,10 +23,10 @@ export const NewsItem = ({ navigation, route }) => {
{newsItem.header}
-
+
)
-
+
const rules = {
image: (
node,
@@ -34,22 +34,22 @@ export const NewsItem = ({ navigation, route }) => {
parent,
styles,
allowedImageHandlers,
- defaultImageHandler,
+ defaultImageHandler
) => {
- const {src, alt} = node.attributes;
- return
+ const { src } = node.attributes
+ return
}
}
return (
-
+
-
-
+
+
renderItemHeader(headerProps, newsItem)}>
-
+
{decodeURIComponent(newsItem.body)}
@@ -67,5 +67,9 @@ const styles = StyleSheet.create({
card: {
flex: 1,
margin: 2
+ },
+ image: {
+ width: '100%',
+ minHeight: 300
}
})
diff --git a/packages/app/lib/backend.js b/packages/app/lib/backend.js
index 14a66e55e..203c3098b 100644
--- a/packages/app/lib/backend.js
+++ b/packages/app/lib/backend.js
@@ -1,14 +1,22 @@
-import moment from 'moment'
-import init from "@skolplattformen/embedded-api"
-export const api = init(fetch) // keep a static version of this object so we can keep the session alive
-
-export const loadChildrenDetails = async (children, what = {news: true}) => await Promise.all(children.map(async child => ({
- ...child,
- news: !what.news ? child.news : await api.getNews(child).catch(err => [{err}]),
- calendar: !what.calendar ? child.calendar : await api.getCalendar(child).catch(err => [{err}]),
- notifications: !what.notifications ? child.notifications : await api.getNotifications(child).catch(err => [{err}]),
- schedule: !what.schedule ? child.schedule : await api.getSchedule(child, moment().startOf('day'), moment().add(7,'days').endOf('day')).catch(err => [{err}]),
- classmates: !what.classmates ? child.classmates : await api.getClassmates(child).catch(err => [{err}]),
- menu: !what.menu ? child.menu : await api.getMenu(child).catch(err => [{err}]),
-})))
+import init from '@skolplattformen/embedded-api'
+export const api = init(fetch) // keep a static version of this object so we can keep the session alive
+export function * fillChild (child) {
+ console.log(`loading notifications for ${child.name}...`)
+ yield api.getNotifications(child).catch(err => Promise.resolve([{ err }])).then(notifications => ({ ...child, notifications }))
+
+ console.log(`loading news for ${child.name}...`)
+ yield api.getNews(child).catch(err => Promise.resolve([{ err }])).then(news => ({ ...child, news }))
+
+ console.log(`loading menu for ${child.name}...`)
+ yield api.getMenu(child).catch(err => Promise.resolve([{ err }])).then(menu => ({ ...child, menu }))
+
+ console.log(`loading calendar for ${child.name}...`)
+ yield api.getCalendar(child).catch(err => Promise.resolve([{ err }])).then(calendar => ({ ...child, calendar }))
+
+ console.log(`loading schedule for ${child.name}...`)
+ yield api.getSchedule(child).catch(err => Promise.resolve([{ err }])).then(schedule => ({ ...child, schedule }))
+
+ console.log(`loading classmates for ${child.name}...`)
+ yield api.getClassmates(child).catch(err => Promise.resolve([{ err }])).then(classmates => ({ ...child, classmates }))
+}