Merge pull request #15 from kolplattformen/release/0.0.2

Release/0.0.2
This commit is contained in:
Erik Hellman 2020-12-23 20:28:11 +01:00 committed by GitHub
commit ff39b1e68a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 2994 additions and 11493 deletions

View File

@ -14,7 +14,7 @@ export default () => {
return (
<>
<IconRegistry icons={EvaIconsPack}/>
<ApplicationProvider {...eva} theme={{...eva.light, ...customization}}>
<ApplicationProvider {...eva} theme={{...eva.light, ...customization}} >
<AppNavigator />
</ApplicationProvider>
</>

View File

@ -67,6 +67,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="color" value="000000" />
<entry key="imagePath" value="/private/var/folders/ry/0xbqnmj96xx4x4pzt83lvpy40000gn/T/ic_android_black_24dp.xml" />
</map>
</option>
@ -79,7 +80,7 @@
<option name="values">
<map>
<entry key="color" value="000000" />
<entry key="imagePath" value="$USER_HOME$/Downloads/Skolplattformen logo.svg" />
<entry key="imagePath" value="$USER_HOME$/Downloads/SpAppIcons/playstore.png" />
<entry key="scalingPercent" value="70" />
</map>
</option>
@ -113,7 +114,8 @@
<option name="values">
<map>
<entry key="backgroundAssetType" value="COLOR" />
<entry key="backgroundColor" value="006ec5" />
<entry key="backgroundColor" value="f5f5f6" />
<entry key="legacyIconShape" value="CIRCLE" />
</map>
</option>
</PersistentState>

View File

@ -96,7 +96,7 @@ def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
def enableProguardInReleaseBuilds = true
/**
* The preferred build flavor of JavaScriptCore.
@ -132,8 +132,8 @@ android {
applicationId "se.kolplattformen.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 15
versionName "0.0.1"
versionCode 20
versionName "0.0.2"
}
splits {
abi {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 399 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#006EC5</color>
<color name="ic_launcher_background">#F5F5F6</color>
</resources>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 KiB

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 KiB

After

Width:  |  Height:  |  Size: 537 KiB

View File

@ -1,6 +1,3 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
production: {
plugins: ["transform-remove-console"]
}
presets: ['module:metro-react-native-babel-preset']
};

View File

@ -1,33 +1,38 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { Divider, List, ListItem, Icon, Text} from '@ui-kitten/components';
import { StyleSheet, Image, View } from 'react-native';
import { Divider, List, ListItem, Icon, Text, Layout} from '@ui-kitten/components';
import moment from 'moment'
import 'moment/locale/sv' // without this line it didn't work
moment.locale('sv')
export const Calendar = ({calendar}) => {
const parseMoment = (date) => moment(date, 'YYYY-MM-DD hh:mm')
const renderItemIcon = (startDate, endDate) =>
(props) => <Icon {...props} fill={parseMoment(startDate).isBefore() && parseMoment(endDate).isAfter() ? '#33f' : '#333'} name={parseMoment(endDate || startDate).isBefore() ? 'calendar' : 'calendar-outline'}/>
(props) => <Icon {...props} fill={moment(startDate).isBefore() && moment(endDate).isAfter() ? '#33f' : '#333'} name={moment(endDate || startDate).isBefore() ? 'calendar' : 'calendar-outline'}/>
const renderItem = ({ item }) => (
<ListItem
title={`${item.title}`}
description={`${moment(item.startDate).calendar()}`}
description={`${moment(item.startDate).locale('sv').calendar()}`}
accessoryLeft={renderItemIcon(item.startDate, item.endDate)}
/>
);
return (
)
return (!calendar?.length ?
<View style={{flex: 1}}>
<Image source={require('../assets/girls.png')} style={{height: 200, width: '100%'}}></Image>
<Text category="h5">Det ser lite tomt ut i kalendern</Text>
</View>
:
<List
style={styles.container}
data={calendar.sort((a, b) => b.startDate < a.startDate)}
ItemSeparatorComponent={Divider}
renderItem={renderItem}
/>
);
};
)
}
const styles = StyleSheet.create({
container: {

View File

@ -1,6 +1,6 @@
import React from 'react'
import { StyleSheet } from 'react-native';
import { TabBar, TopNavigation, TopNavigationAction, Tab, TabView, Layout, Text, Divider, Icon } from '@ui-kitten/components'
import { TabBar, TopNavigation, TopNavigationAction, Tab, TabView, OverflowMenu, MenuItem, Layout, Text, Divider, Icon } from '@ui-kitten/components'
import { NewsList } from './newsList.component'
import { Calendar } from './calendar.component'
import { Classmates } from './classmates.component'
@ -10,6 +10,7 @@ import moment from 'moment'
export const Child = ({route, navigation}) => {
const [selectedIndex, setSelectedIndex] = React.useState(0)
const { child, color } = route.params;
const [menuVisible, setMenuVisible] = React.useState(false);
const NewsIcon = (props) => (
<Icon {...props} name='activity-outline'/>
@ -22,13 +23,20 @@ export const Child = ({route, navigation}) => {
<Icon {...props} name='people-outline'/>
)
const EditIcon = (props) => (
<Icon {...props} name='edit'/>
)
const SettingsIcon = (props) => (
<Icon {...props} name='options-2-outline'/>
)
const BackIcon = (props) => (
<Icon {...props} name='arrow-back' />
)
const MenuIcon = (props) => (
<Icon {...props} name='more-vertical'/>
)
const BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={navigateBack} />
)
@ -37,10 +45,36 @@ export const Child = ({route, navigation}) => {
navigation.goBack()
}
const toggleMenu = () => {
setMenuVisible(!menuVisible);
}
const renderMenuAction = () => (
<TopNavigationAction icon={MenuIcon} onPress={toggleMenu}/>
)
const renderRightActions = () => (
<React.Fragment>
<OverflowMenu
anchor={renderMenuAction}
visible={menuVisible}
backdropStyle={styles.backdrop}
onBackdropPress={toggleMenu}>
<MenuItem accessoryLeft={SettingsIcon} title='Anmäl frånvaro'/>
</OverflowMenu>
</React.Fragment>
);
return (
<SafeAreaView style={{ flex: 1 }} style={{...styles.topBar, color: color}}>
<TopNavigation title={ child.name} alignment='center' accessoryLeft={BackAction} style={{...styles.topBar, color: color}}/>
<TabView selectedIndex={selectedIndex} tabBarStyle={{color}} indicatorStyle={{backgroundColor: color, color}} onSelect={index => setSelectedIndex(index)}>
<TopNavigation title={ child.name}
alignment='center'
accessoryLeft={BackAction}
accessoryRight={renderRightActions}
style={styles.topBar}/>
<TabView selectedIndex={selectedIndex} onSelect={index => setSelectedIndex(index)}>
<Tab title="Nyheter" icon={NewsIcon}>
<Layout style={styles.tabContainer}>
<NewsList news={child.news} />
@ -48,27 +82,17 @@ export const Child = ({route, navigation}) => {
</Tab>
<Tab title="Schema" icon={CalendarIcon}>
<Layout style={styles.tabContainer}>
<Calendar calendar={[...child.calendar, ...child.schedule].filter(a => moment(a.startDate).isAfter(moment().startOf('day')) ) }></Calendar>
<Calendar calendar={[...child.calendar, ...child.schedule].filter(a => moment(a.startDate, 'YYYY-MM-DD hh:mm').isAfter(moment().startOf('day')) ) }></Calendar>
</Layout>
</Tab>
<Tab title="Klassen" icon={ClassIcon}>
<Layout style={styles.tabContainer}>
<Text category='h5'>
Klass {child.classmates.length ? child.classmates[0].className : ''}
Klass {child.classmates?.length ? child.classmates[0].className : ''}
</Text>
<Classmates classmates={child.classmates}/>
</Layout>
</Tab>
<Tab title="Inställningar" icon={SettingsIcon}>
<Layout style={styles.tabContainer}>
<Text category='h5'>
Inställningar
</Text>
<Text category='c2'>
Här kommer du kunna sjukanmäla och göra andra bra grejer...
</Text>
</Layout>
</Tab>
</TabView>
</SafeAreaView>
@ -83,8 +107,11 @@ const styles = StyleSheet.create({
tabContainer: {
alignItems: 'flex-start',
justifyContent: 'flex-start',
paddingTop: 5,
paddingTop: 10,
paddingLeft: 10,
flexDirection: 'column'
},
backdrop: {
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
})

View File

@ -1,14 +1,13 @@
import React, {useState, useMemo, useCallback, useEffect } from 'react'
import { StyleSheet, View, Image } from 'react-native'
import { SafeAreaView } from 'react-native'
import useFetch from 'use-http'
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 '@rnhooks/async-storage'
import {api} from '../lib/backend'
import {useAsyncStorage} from 'use-async-storage'
import {api, loadChildrenDetails} from '../lib/backend'
const colors = ['#F2FDD3', '#CEFEF1', '#FEF2DC', '#FEE2E3', '#CB4D93']
const colors = ['primary', 'success', 'info', 'warning', 'danger']
const BackIcon = (props) => (
<Icon {...props} name='arrow-back' />
@ -27,46 +26,34 @@ const PeopleIcon = (style) => (
)
export const Children = ({navigation}) => {
const [savedChildren, setSavedChildren, clearSavedChildren] = useAsyncStorage('@children', '[]')
const [children, setChildren] = useState(JSON.parse(savedChildren) || [])
const [children, setChildren] = useAsyncStorage('@children', [])
useEffect(() => {
const load = async () => {
try {
const children = await api.getChildren()
if (!children.length) {
const childrenList = children?.length || await api.getChildren()
if (!childrenList?.length) {
console.log('no children found')
return navigation.navigate('Login', {error: 'Hittar inga barn med det personnumret'})
}
console.log('got children', children)
//setChildren(children)
//TODO: lazy load these
const fullChildren = await Promise.all(children.map(async child => ({
...child,
news: await api.getNews(child),
calendar: await api.getCalendar(child),
classmates: await api.getClassmates(child),
schedule: await api.getSchedule(child, moment().startOf('day'), moment().add(7,'days').endOf('day')),
menu: await api.getMenu(child),
notifications: await api.getNotifications(child),
})))
console.log('full', fullChildren)
// 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)
setSavedChildren(JSON.stringify(savedChildren))
} catch (err) {
console.log('err', err)
navigation.navigate('Login', {error: 'Fel uppstod, försök igen'})
}
}
load()
}, [])
if (api.isLoggedIn) load()
}, [api.isLoggedIn])
return <ChildrenView navigation={navigation} children={children}></ChildrenView>
}
export const ChildrenView = ({ navigation, children }) => {
export const ChildrenView = ({ navigation, children, eva }) => {
@ -88,9 +75,9 @@ export const ChildrenView = ({ navigation, children }) => {
)
const Header = (props, info, i) => (
<View {...props} style={{flexDirection: 'row', backgroundColor: colors[i % colors.length]}}>
<View {...props} style={{flexDirection: 'row'}}>
<View style={{margin: 20}}>
<Avatar source={require('../assets/avatar.png')} />
<Avatar source={require('../assets/avatar.png')} shape="square" />
</View>
<View style={{margin: 20}}>
<Text category='h6'>
@ -117,7 +104,7 @@ export const ChildrenView = ({ navigation, children }) => {
status='control'
size='small'
accessoryLeft={CalendarIcon}>
{`${(info.item.notifications || []).filter(c => moment(c.startDate).isSame('day') ).length} idag`}
{`${(info.item.notifications || []).filter(c => moment(c.startDate, 'YYYY-MM-DD hh:mm').isSame('day') ).length} idag`}
</Button>
<Button
style={styles.iconButton}
@ -130,36 +117,43 @@ export const ChildrenView = ({ navigation, children }) => {
)
const renderItem = (info) => {
const color = colors[info.index % colors.length]
return <Card
style={{...styles.card, backgroundColor: colors[info.index % colors.length]}}
style={{...styles.card}}
appearance="filled"
status={color}
header={headerProps => Header(headerProps, info, info.index)}
footer={footerProps => Footer(footerProps, info)}
onPress={() => navigateChild(info.item, colors[info.index % colors.length])}>
onPress={() => navigateChild(info.item, color)}>
{([...info.item.calendar, ...info.item.schedule].filter(a => moment(a.startDate).isSame('day'))).map((calendarItem, i) => <Text appearance='hint' category='c1' key={i}>
{`${calendarItem.title}`}
</Text>
{([...info.item.calendar, ...info.item.schedule].filter(a => moment(a.startDate, 'YYYY-MM-DD hh:mm').isSame('day'))).map((calendarItem, i) =>
<Text appearance='hint' category='c1' key={i}>
{`${calendarItem.title}`}
</Text>
)}
</Card>
}
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }}>
<TopNavigation title='Dina barn' alignment='center' accessoryLeft={BackAction} />
<SafeAreaView style={{ flex: 1, backgroundColor: 'transparent'}}>
<TopNavigation title='Dina barn' alignment='center' accessoryLeft={BackAction} />
<Divider/>
<Layout style={{ flex: 1 }} level='1'>
{children.length ? <List
style={styles.container}
contentContainerStyle={styles.contentContainer}
data={children}
renderItem={renderItem} />
{children?.length ? <Layout style={{ flex: 1, justifyContent: 'space-between' }}>
<List
style={styles.container}
contentContainerStyle={styles.contentContainer}
data={children}
renderItem={renderItem} />
</Layout>
: <Layout style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Image source={require('../assets/undraw_teaching_f1cm.png')} style={{height: 400, width: '100%'}}></Image>
<Image source={require('../assets/girls.png')} style={{height: 400, width: '100%'}}></Image>
<View style={{flexDirection: 'row'}}>
<Spinner size='large'/>
<Spinner size='large' status="warning"/>
<Text category='h1' style={{marginLeft: 10, marginTop: -7}}>Laddar...</Text>
</View>
</Layout>}
</Layout>
</SafeAreaView>
)

View File

@ -1,9 +1,9 @@
import React, { useEffect } from 'react'
import { Platform } from 'react-native'
import { SafeAreaView, StyleSheet, Image, Linking, KeyboardAvoidingView, View } from 'react-native'
import { SafeAreaView, StyleSheet, Image, Linking, KeyboardAvoidingView, TouchableOpacity, View } from 'react-native'
import { Button, Icon, Modal, Card, Text, ImageBackground, Divider, Layout, TopNavigation, Input } from '@ui-kitten/components'
import Personnummer from 'personnummer'
import useAsyncStorage from '@rnhooks/async-storage'
import {useAsyncStorage} from 'use-async-storage'
import { ScrollView } from 'react-native-gesture-handler'
import {api} from '../lib/backend'
@ -17,21 +17,11 @@ export const Login = ({ navigation, route }) => {
const [argument, setArgument] = React.useState('öppna')
const [error, setError] = React.useState(null)
const [hasBankId, setHasBankId] = React.useState(false)
const [socialSecurityNumber, setSocialSecurityNumber, clearSocialSecurityNumber] = useAsyncStorage('@socialSecurityNumber')
const [socialSecurityNumber, setSocialSecurityNumber] = useAsyncStorage('@socialSecurityNumber')
const [cookie, setCookie, clearCookie] = useAsyncStorage('@cookie')
useEffect(() => {
setValid(Personnummer.valid(socialSecurityNumber))
const url = Platform.OS == 'ios' ? 'https://app.bankid.com/' : 'bankid:///'
setHasBankId(Linking.canOpenURL(url))
if (route.params?.error) setError(route.params.error)
console.log('effect')
if (cookie) {
console.log('cookie', cookie)
api.setSessionCookie(cookie)
setLoggedIn(true)
navigateToChildren()
}
}, [socialSecurityNumber, cookie])
useEffect(() => {
@ -88,9 +78,9 @@ export const Login = ({ navigation, route }) => {
loginStatus.on("ERROR", () => setError('Inloggningen misslyckades, försök igen!') && setVisible(false))
loginStatus.on("OK", async () => {
setLoggedIn(true)
navigateToChildren()
const session = api.getSessionCookie()
setCookie(session)
navigateToChildren()
setVisible(false)
})
}
@ -107,8 +97,8 @@ export const Login = ({ navigation, route }) => {
<TopNavigation title={`Skolplattformen.org - det ${argument} alternativet`} alignment='center'/>
{loggedIn ? <Layout style={{ flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Image source={require('../assets/man.png')} style={{maxHeight: 300, width: '100%' }}></Image>
<View style={{ margin: 30, justifyContent: 'flex-start', alignItems: 'flex-start', flex: 1}}>
<Image source={require('../assets/man.png')} style={{maxHeight: 300, width: '100%', borderBottomWidth:1 }}></Image>
<View style={{ marginTop: 80, justifyContent: 'flex-start', alignItems: 'flex-start', flex: 1}}>
<Text category="h4">{socialSecurityNumber}</Text>
<Text>{error ? error : 'Hurra, du är inloggad!'}</Text>
<Button
@ -129,25 +119,30 @@ export const Login = ({ navigation, route }) => {
</View>
</Layout>
: <KeyboardAvoidingView>
<Layout style={{ flex: 1 }}>
<Image source={require('../assets/children.png')} style={{height: 270, width: '100%'}}></Image>
<View style={{ flex: 1, justifyContent: 'flex-start', alignItems: 'flex-start', paddingHorizontal: 20}}>
<Text category="h3">Vårdnadshavare</Text>
<Layout style={{ flex: 1 }}>
{
// hidden easter egg, just touch the image to login without bankId if you still have a valid token
}
<TouchableOpacity onPress={navigateToChildren} style={{height: 320}}>
<Image source={require('../assets/boys.png')} style={{height: 320, marginTop: -20, marginLeft: -10, width: '110%'}}></Image>
</TouchableOpacity>
<View style={{ flex: 1, justifyContent: 'flex-start', alignItems: 'flex-start', paddingHorizontal: 20}}>
<Input label='Personnummer' autoFocus={true} value={socialSecurityNumber}
style={{minHeight:70}}
accessoryLeft = {PersonIcon}
caption={error && error.message || ''}
onChangeText = {text => handleInput(text)}
placeholder="Ditt personnr (10 eller 12 siffror)"/>
<Button onPress={startLogin} style={{width: "100%"}}
appearence='ghost'
disabled={!valid}
status='primary'
accessoryRight={SecureIcon}
size='medium'>
Öppna BankID
</Button>
</View>
style={{minHeight:70}}
accessoryLeft = {PersonIcon}
keyboardType='numeric'
caption={error && error.message || ''}
onChangeText = {text => handleInput(text)}
placeholder="Ditt personnr (10 eller 12 siffror)"/>
<Button onPress={startLogin} style={{width: "100%"}}
appearence='ghost'
disabled={!valid}
status='primary'
accessoryRight={SecureIcon}
size='medium'>
Öppna BankID
</Button>
</View>
</Layout>
</KeyboardAvoidingView>
}
@ -157,7 +152,7 @@ export const Login = ({ navigation, route }) => {
backdropStyle={styles.backdrop}
onBackdropPress={() => setVisible(false)}>
<Card disabled={true}>
{hasBankId ? <Text style={{margin: 10}}>Öppnar BankID. Växla tillbaka till hit sen.</Text> : <Text style={{margin: 10}}>Väntar på BankID...</Text>}
{hasBankId ? <Text style={{margin: 10}}>Öppnar BankID. Växla tillbaka hit sen.</Text> : <Text style={{margin: 10}}>Väntar på BankID...</Text>}
<Button
visible={!loggedIn}

View File

@ -1,12 +1,11 @@
import React from 'react'
import { StatusBar} from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
import useAsyncStorage from '@rnhooks/async-storage'
import { Login } from './login.component'
import { Children } from './children.component'
import { Child } from './child.component'
import { NewsItem } from './newsItem.component'
import { Provider } from 'use-http'
const { Navigator, Screen } = createStackNavigator()
@ -20,22 +19,7 @@ const HomeNavigator = () => (
)
export const AppNavigator = () => {
const [jwt, setJwt, clearJwt] = useAsyncStorage('@jwt')
const options = {
interceptors: {
request: async ({ options, url, path, route }) => {
console.log('requesting', url, path, route, options)
return options
}
},
headers: {
Accept: 'application/json',
authorization: 'Bearer ' + jwt,
}
}
return <NavigationContainer>
<Provider url='https://api.skolplattformen.org' options={options}>
<HomeNavigator/>
</Provider>
<HomeNavigator/>
</NavigationContainer>
}

View File

@ -23,8 +23,23 @@ export const NewsItem = ({ navigation, route }) => {
<Text category='h3'>
{newsItem.header}
</Text>
<Image source={{ uri: `https://etjanst.stockholm.se/Vardnadshavare/inloggad2/NewsBanner?url=${newsItem.imageUrl}`}} style={{width: '100%', minHeight: 300}}></Image>
</View>
)
const rules = {
image: (
node,
children,
parent,
styles,
allowedImageHandlers,
defaultImageHandler,
) => {
const {src, alt} = node.attributes;
return <Image source={{uri : `https://elevstockholm.sharepoint.com${src}`}} style={{width: '100%', minHeight: 300}}></Image>
}
}
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }} >
@ -34,7 +49,7 @@ export const NewsItem = ({ navigation, route }) => {
<Layout style={styles.topContainer} level='1'>
<ScrollView>
<Card style={styles.card} header={headerProps => renderItemHeader(headerProps, newsItem)}>
<Markdown style={{ body: {color: 'black'}, heading1: {color: 'black'} }}>
<Markdown rules={rules} style={{ body: {color: 'black', fontSize: 17, lineHeight: 23}, heading1: {color: 'black'} }}>
{decodeURIComponent(newsItem.body)}
</Markdown>
</Card>

View File

@ -1,7 +1,6 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
import { SafeAreaView, StyleSheet, View, Image } from 'react-native'
import { Card, List, Text, Layout } from '@ui-kitten/components'
import { Image } from 'react-native-svg'
import { NavigationContainer } from '@react-navigation/native'
import { useNavigation } from '@react-navigation/native'
@ -21,28 +20,27 @@ export const NewsList = ({news}) => {
style={styles.card}
onPress={() => navigation.navigate('NewsItem', {newsItem: info.item})}
header={headerProps => renderItemHeader(headerProps, info)}>
<Image source={{ uri: `https://etjanst.stockholm.se/Vardnadshavare/inloggad2/NewsBanner?url=${info.item.imageUrl}`}} style={{height: 300}}></Image>
</Card>
)
return (
<Layout style={styles.topContainer} level='1'>
<List
style={styles.container}
contentContainerStyle={styles.contentContainer}
data={news}
renderItem={renderItem} />
</Layout>
<List
style={styles.container}
contentContainerStyle={styles.contentContainer}
data={news}
renderItem={renderItem} />
)
}
const styles = StyleSheet.create({
topContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
},
card: {
flex: 1,
margin: 2,
},
contentContainer: {
paddingRight: 10,
paddingBottom: 330
}
});

View File

@ -0,0 +1,22 @@
{
"strict": {
"border-radius": 50
},
"components": {
"Button": {
"meta": {},
"appearances": {
"filled": {
"mapping": {},
"variantGroups": {
"status": {
"primary": {
"backgroundColor": "blue"
}
}
}
}
}
}
}
}

View File

@ -291,7 +291,7 @@
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = BSE2J6442R;
DevelopmentTeam = 59292HY5Q8;
LastSwiftMigration = 1120;
};
2D02E47A1E0B4A5D006451C7 = {
@ -629,8 +629,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 15;
DEVELOPMENT_TEAM = BSE2J6442R;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 59292HY5Q8;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
@ -638,7 +638,7 @@
);
INFOPLIST_FILE = Skolplattformen/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 0.0.1;
MARKETING_VERSION = 0.0.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -658,11 +658,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 15;
DEVELOPMENT_TEAM = BSE2J6442R;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 59292HY5Q8;
INFOPLIST_FILE = Skolplattformen/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 0.0.1;
MARKETING_VERSION = 0.0.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",

View File

@ -13,29 +13,28 @@
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_launcher-playstore" id="AD3-Uy-RPP">
<rect key="frame" x="49.156626506024054" y="235" width="291.00000000000011" height="270.00000000000006"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Skolplattformen" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="0.0" y="100" width="390" height="43"/>
<rect key="frame" x="60.666666666666657" y="100" width="268.66666666666674" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.99999552970000005" green="1" blue="0.99607855079999996" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="appstore" id="bMh-M1-Kl4">
<rect key="frame" x="45" y="192" width="300" height="300"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" red="0.019342456009999998" green="0.42363536359999998" blue="0.74905878309999996" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" red="0.99999552970000005" green="1" blue="0.99607855079999996" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstItem="AD3-Uy-RPP" firstAttribute="top" secondItem="kId-c2-rCX" secondAttribute="bottom" constant="92" id="Enz-w3-qGu"/>
<constraint firstAttribute="trailing" secondItem="kId-c2-rCX" secondAttribute="trailing" id="bHX-Nr-atg"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="e34-cY-Leb"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="100" id="msO-ON-KBD"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="ddS-XM-xPo"/>
<constraint firstItem="bMh-M1-Kl4" firstAttribute="top" secondItem="kId-c2-rCX" secondAttribute="bottom" constant="49" id="juP-om-veb"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<point key="canvasLocation" x="546.15384615384619" y="454.9763033175355"/>
</view>
</objects>
<resources>
<image name="ic_launcher-playstore" width="512" height="512"/>
<image name="appstore" width="1024" height="1024"/>
</resources>
</document>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1022 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "ic_launcher-playstore.png",
"filename" : "appstore.png",
"idiom" : "universal",
"scale" : "1x"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>$kolplattformen</string>
<string>Skolplattformen</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -48,8 +48,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

View File

@ -1,3 +1,14 @@
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}]),
})))

File diff suppressed because it is too large Load Diff

View File

@ -17,11 +17,11 @@
"@react-navigation/material-top-tabs": "^5.3.10",
"@react-navigation/native": "^5.8.10",
"@react-navigation/stack": "^5.12.8",
"@rnhooks/async-storage": "0.0.1",
"@skolplattformen/embedded-api": "^0.9.0",
"@ui-kitten/components": "5.0.0",
"@ui-kitten/eva-icons": "5.0.0",
"buffer": "^6.0.3",
"faker": "^5.1.0",
"personnummer": "^3.1.1",
"react": "16.11.0",
"react-native": "0.62.2",
@ -36,7 +36,7 @@
"react-native-svg": "^12.1.0",
"react-native-svg-transformer": "^0.14.3",
"react-native-tab-view": "^2.15.2",
"use-http": "^1.0.16"
"use-async-storage": "^1.2.0"
},
"devDependencies": {
"@babel/core": "^7.6.2",