Merge branch 'main' into refactor
This commit is contained in:
commit
77605cd427
|
@ -39,7 +39,7 @@ api.register({
|
||||||
const token = await backend.login(socialSecurityNumber)
|
const token = await backend.login(socialSecurityNumber)
|
||||||
return res.status(200).json(token)
|
return res.status(200).json(token)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.status(500).json({ message: err.message, stack: err.stack })
|
return res.status(err.status || 500).json({ message: err.message, stack: err.stack })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
waitForToken: async (c, req, res) => {
|
waitForToken: async (c, req, res) => {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const camel = require('camelcase-keys')
|
|
||||||
const h2m = require('h2m')
|
const h2m = require('h2m')
|
||||||
const {htmlDecode} = require('js-htmlencode')
|
const {htmlDecode} = require('js-htmlencode')
|
||||||
const urls = require('./urls')
|
const urls = require('./urls')
|
||||||
|
@ -76,11 +75,12 @@ const getCalendar = async (childId, cookie) => {
|
||||||
id,
|
id,
|
||||||
description,
|
description,
|
||||||
location,
|
location,
|
||||||
startDate,
|
startDate: moment(startDate, 'YYYY-MM-DD hh:mm').toISOString(),
|
||||||
endDate,
|
endDate: moment(endDate, 'YYYY-MM-DD hh:mm').toISOString(),
|
||||||
allDay
|
allDay
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getNotifications = async (childId, cookie) => {
|
const getNotifications = async (childId, cookie) => {
|
||||||
const url = urls.notifications(childId)
|
const url = urls.notifications(childId)
|
||||||
|
@ -141,8 +141,8 @@ const getSchedule = async (childId, cookie) => {
|
||||||
id,
|
id,
|
||||||
description,
|
description,
|
||||||
location,
|
location,
|
||||||
startDate,
|
startDate: moment(startDate, 'YYYY-MM-DD hh:mm').toISOString(),
|
||||||
endDate,
|
endDate: moment(endDate, 'YYYY-MM-DD hh:mm').toISOString(),
|
||||||
allDay,
|
allDay,
|
||||||
mentor
|
mentor
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -7,16 +7,14 @@ import {
|
||||||
import { EvaIconsPack } from '@ui-kitten/eva-icons';
|
import { EvaIconsPack } from '@ui-kitten/eva-icons';
|
||||||
import * as eva from '@eva-design/eva';
|
import * as eva from '@eva-design/eva';
|
||||||
import customization from './design/customization.json';
|
import customization from './design/customization.json';
|
||||||
import children from './output.json';
|
|
||||||
|
|
||||||
import {ChildList} from './components/childList.component'
|
import { AppNavigator } from './components/navigation.component';
|
||||||
import {AppNavigator} from './components/tabs.component'
|
|
||||||
|
|
||||||
export default () => (
|
export default () => (
|
||||||
<>
|
<>
|
||||||
<IconRegistry icons={EvaIconsPack}/>
|
<IconRegistry icons={EvaIconsPack}/>
|
||||||
<ApplicationProvider {...eva} theme={{...eva.light, customization}}>
|
<ApplicationProvider {...eva} theme={{...eva.light, ...customization}}>
|
||||||
<ChildList children={children} />
|
<AppNavigator />
|
||||||
</ApplicationProvider>
|
</ApplicationProvider>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
|
@ -1,11 +1,19 @@
|
||||||
# `app`
|
# `app`
|
||||||
|
|
||||||
> TODO: description
|
This is a demo app for using the API
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
Clone the repo and make sure you have react-native installed:
|
||||||
const app = require('app');
|
|
||||||
|
|
||||||
// TODO: DEMONSTRATE API
|
npm i -g react-native
|
||||||
```
|
|
||||||
|
To run the app in a simulator:
|
||||||
|
|
||||||
|
react-native run-ios
|
||||||
|
|
||||||
|
## TODO:
|
||||||
|
[ ] Välj barn
|
||||||
|
[ ] Login
|
||||||
|
[ ] Anmäl frånvaro
|
||||||
|
[ ] Settings
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import { Divider, List, ListItem, Icon, Text} from '@ui-kitten/components';
|
import { Divider, List, ListItem, Icon, Text} from '@ui-kitten/components';
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
export const Calendar = ({calendar}) => {
|
export const Calendar = ({calendar}) => {
|
||||||
|
|
||||||
const renderItemIcon = (props) => (
|
const parseMoment = (date) => moment(date, 'YYYY-MM-DD hh:mm')
|
||||||
<Icon {...props} name='calendar-outline'/>
|
|
||||||
);
|
const renderItemIcon = (startDate, endDate) =>
|
||||||
|
(props) => <Icon {...props} fill={parseMoment(startDate).isBefore() && parseMoment(endDate).isAfter() ? '#33f' : '#333'} name={parseMoment(endDate || startDate).isBefore() ? 'calendar' : 'calendar-outline'}/>
|
||||||
|
|
||||||
const renderItem = ({ item }) => (
|
const renderItem = ({ item }) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
title={`${item.title}`}
|
title={`${item.title}`}
|
||||||
description={`${item.startDate}`}
|
description={`${moment(item.startDate).calendar()}`}
|
||||||
accessoryLeft={renderItemIcon}
|
accessoryLeft={renderItemIcon(item.startDate, item.endDate)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ export const Calendar = ({calendar}) => {
|
||||||
return (
|
return (
|
||||||
<List
|
<List
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
data={calendar}
|
data={calendar.sort((a, b) => b.startDate < a.startDate)}
|
||||||
ItemSeparatorComponent={Divider}
|
ItemSeparatorComponent={Divider}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
/>
|
/>
|
||||||
|
@ -29,7 +31,12 @@ export const Calendar = ({calendar}) => {
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
maxHeight: 200,
|
|
||||||
width: "100%"
|
width: "100%"
|
||||||
},
|
},
|
||||||
|
ongoing: {
|
||||||
|
color: 'red'
|
||||||
|
},
|
||||||
|
normal: {
|
||||||
|
color: 'black'
|
||||||
|
}
|
||||||
});
|
});
|
|
@ -0,0 +1,83 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { TabBar, TopNavigation, TopNavigationAction, Tab, TabView, Layout, Text, Divider, Icon } from '@ui-kitten/components'
|
||||||
|
import { NewsList } from './newsList.component'
|
||||||
|
import { Calendar } from './calendar.component'
|
||||||
|
import { Classmates } from './classmates.component'
|
||||||
|
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
export const Child = ({route, navigation}) => {
|
||||||
|
const [selectedIndex, setSelectedIndex] = React.useState(0)
|
||||||
|
const { child } = route.params;
|
||||||
|
|
||||||
|
const NewsIcon = (props) => (
|
||||||
|
<Icon {...props} name='activity-outline'/>
|
||||||
|
)
|
||||||
|
const CalendarIcon = (props) => (
|
||||||
|
<Icon {...props} name='calendar-outline'/>
|
||||||
|
)
|
||||||
|
|
||||||
|
const ClassIcon = (props) => (
|
||||||
|
<Icon {...props} name='people-outline'/>
|
||||||
|
)
|
||||||
|
|
||||||
|
const SettingsIcon = (props) => (
|
||||||
|
<Icon {...props} name='options-2-outline'/>
|
||||||
|
)
|
||||||
|
|
||||||
|
const BackIcon = (props) => (
|
||||||
|
<Icon {...props} name='arrow-back' />
|
||||||
|
)
|
||||||
|
const BackAction = () => (
|
||||||
|
<TopNavigationAction icon={BackIcon} onPress={navigateBack} />
|
||||||
|
)
|
||||||
|
|
||||||
|
const navigateBack = () => {
|
||||||
|
navigation.goBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={{ flex: 1 }}>
|
||||||
|
<TopNavigation title={ child.name} alignment='center' accessoryLeft={BackAction} />
|
||||||
|
<TabView selectedIndex={selectedIndex} onSelect={index => setSelectedIndex(index)}>
|
||||||
|
<Tab title="Nyheter" icon={NewsIcon}>
|
||||||
|
<Layout style={styles.tabContainer}>
|
||||||
|
<NewsList news={child.news} />
|
||||||
|
</Layout>
|
||||||
|
</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>
|
||||||
|
</Layout>
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Klassen" icon={ClassIcon}>
|
||||||
|
<Layout style={styles.tabContainer}>
|
||||||
|
<Text category='h5'>
|
||||||
|
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>
|
||||||
|
</Layout>
|
||||||
|
</Tab>
|
||||||
|
</TabView>
|
||||||
|
|
||||||
|
</SafeAreaView>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
tabContainer: {
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
paddingTop: 5,
|
||||||
|
paddingLeft: 10,
|
||||||
|
flexDirection: 'column'
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,54 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { StyleSheet } from 'react-native';
|
|
||||||
import { Layout, Text, ViewPager, Button, Icon } from '@ui-kitten/components';
|
|
||||||
import { NewsList } from './newsList.component'
|
|
||||||
import { Calendar } from './calendar.component'
|
|
||||||
import { ChildTopNavigation } from './childTopNavigation.component';
|
|
||||||
import { BottomNavigation, BottomNavigationTab } from '@ui-kitten/components';
|
|
||||||
|
|
||||||
const SelectCategory = ({child}) => {
|
|
||||||
|
|
||||||
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BottomNavigation
|
|
||||||
selectedIndex={selectedIndex}
|
|
||||||
onSelect={index => setSelectedIndex(index)}>
|
|
||||||
<BottomNavigationTab title='Nyheter'/>
|
|
||||||
<BottomNavigationTab title='Kalender'/>
|
|
||||||
<BottomNavigationTab title='Klassen'/>
|
|
||||||
</BottomNavigation>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const ChildList = ({children}) => {
|
|
||||||
|
|
||||||
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ViewPager
|
|
||||||
selectedIndex={selectedIndex}
|
|
||||||
onSelect={index => setSelectedIndex(index)}>
|
|
||||||
{children.map(child =>
|
|
||||||
<Layout
|
|
||||||
key={child.id}
|
|
||||||
style={{...styles.tab}}
|
|
||||||
level='2'>
|
|
||||||
<ChildTopNavigation child={child}></ChildTopNavigation>
|
|
||||||
<SelectCategory>
|
|
||||||
</SelectCategory>
|
|
||||||
<NewsList news={child.news} />
|
|
||||||
<Calendar calendar={[...child.calendar, ...child.schedule] }></Calendar>
|
|
||||||
</Layout>
|
|
||||||
)}
|
|
||||||
</ViewPager>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
tab: {
|
|
||||||
height: '100%',
|
|
||||||
paddingTop: 50,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,63 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { StyleSheet, View } from 'react-native'
|
|
||||||
import { Avatar, Icon, MenuItem, OverflowMenu, Text, TopNavigation, TopNavigationAction } from '@ui-kitten/components'
|
|
||||||
|
|
||||||
const MenuIcon = (props) => (
|
|
||||||
<Icon {...props} name='more-vertical' />
|
|
||||||
)
|
|
||||||
|
|
||||||
const InfoIcon = (props) => (
|
|
||||||
<Icon {...props} name='info' />
|
|
||||||
)
|
|
||||||
|
|
||||||
const LogoutIcon = (props) => (
|
|
||||||
<Icon {...props} name='log-out' />
|
|
||||||
)
|
|
||||||
|
|
||||||
export const ChildTopNavigation = ({child}) => {
|
|
||||||
|
|
||||||
const [menuVisible, setMenuVisible] = React.useState(false)
|
|
||||||
|
|
||||||
const toggleMenu = () => {
|
|
||||||
setMenuVisible(!menuVisible)
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderMenuAction = () => (
|
|
||||||
<TopNavigationAction icon={MenuIcon} onPress={toggleMenu} />
|
|
||||||
)
|
|
||||||
|
|
||||||
const renderOverflowMenuAction = () => (
|
|
||||||
<React.Fragment>
|
|
||||||
<OverflowMenu anchor={renderMenuAction} visible={menuVisible} onBackdropPress={toggleMenu}>
|
|
||||||
<MenuItem accessoryLeft={InfoIcon} title='Sjukanmälan' />
|
|
||||||
<MenuItem accessoryLeft={InfoIcon} title='Kontakta' />
|
|
||||||
<MenuItem accessoryLeft={LogoutIcon} title='Logga ut' />
|
|
||||||
</OverflowMenu>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
|
|
||||||
const renderTitle = (props) => (
|
|
||||||
<View style={styles.titleContainer}>
|
|
||||||
<Icon {...props} style={styles.logo} name='person'/>
|
|
||||||
<Text {...props}>
|
|
||||||
{child.name}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TopNavigation title={renderTitle} accessoryRight={renderOverflowMenuAction} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
titleContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center'
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
marginHorizontal: 16,
|
|
||||||
width: 16,
|
|
||||||
height: 16
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { StyleSheet, View } from 'react-native'
|
||||||
|
import { SafeAreaView } from 'react-native'
|
||||||
|
import moment from 'moment'
|
||||||
|
import { Divider, Button, Icon, Layout, Text, TopNavigation, TopNavigationAction, List, Card, Avatar } from '@ui-kitten/components'
|
||||||
|
import children from '../output.json'
|
||||||
|
|
||||||
|
const BackIcon = (props) => (
|
||||||
|
<Icon {...props} name='arrow-back' />
|
||||||
|
)
|
||||||
|
|
||||||
|
const NotificationIcon = (style) => (
|
||||||
|
<Icon {...style} name='activity-outline' />
|
||||||
|
)
|
||||||
|
|
||||||
|
const CalendarIcon = (style) => (
|
||||||
|
<Icon {...style} name='calendar-outline' />
|
||||||
|
)
|
||||||
|
|
||||||
|
const PeopleIcon = (style) => (
|
||||||
|
<Icon {...style} name='people-outline' />
|
||||||
|
)
|
||||||
|
|
||||||
|
export const Children = ({ navigation }) => {
|
||||||
|
|
||||||
|
const abbrevations = {
|
||||||
|
G: 'Gymnasiet',
|
||||||
|
GR: 'Grundskolan',
|
||||||
|
F: 'Förskoleklass',
|
||||||
|
}
|
||||||
|
const navigateBack = () => {
|
||||||
|
navigation.goBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigateChild = (child) => {
|
||||||
|
navigation.navigate('Child', {child})
|
||||||
|
}
|
||||||
|
|
||||||
|
const BackAction = () => (
|
||||||
|
<TopNavigationAction icon={BackIcon} onPress={navigateBack} />
|
||||||
|
)
|
||||||
|
|
||||||
|
const Header = (props, info) => (
|
||||||
|
<View {...props}>
|
||||||
|
<Text category='h6'>
|
||||||
|
{info.item.name.split('(')[0]}
|
||||||
|
</Text>
|
||||||
|
<Text category='s1'>
|
||||||
|
{`${info.item.status.split(';').map(status => abbrevations[status]).join(', ')}`}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
|
const Footer = (props, info) => (
|
||||||
|
<View style={styles.itemFooter}>
|
||||||
|
<Button
|
||||||
|
style={styles.iconButton}
|
||||||
|
status='control'
|
||||||
|
size='small'
|
||||||
|
accessoryLeft={NotificationIcon}>
|
||||||
|
{`${info.item.news.length}`}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={styles.iconButton}
|
||||||
|
status='control'
|
||||||
|
size='small'
|
||||||
|
accessoryLeft={CalendarIcon}>
|
||||||
|
{`${info.item.notifications.filter(c => moment(c.startDate).isSame('day') ).length}`}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={styles.iconButton}
|
||||||
|
status='control'
|
||||||
|
size='small'
|
||||||
|
accessoryLeft={PeopleIcon}>
|
||||||
|
{`${info.item.classmates.length} i klassen`}
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
|
const renderItem = (info) => (
|
||||||
|
<Card
|
||||||
|
style={styles.card}
|
||||||
|
header={headerProps => Header(headerProps, info)}
|
||||||
|
footer={footerProps => Footer(footerProps, info)}
|
||||||
|
onPress={() => navigateChild(info.item)}>
|
||||||
|
{info.item.menu.map(menu =>
|
||||||
|
<Text appearance='hint' category='c1'>
|
||||||
|
{`${menu.title.split(' -')[0]} - ${menu.description.split('<br/>')[0]}`}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={{ flex: 1 }}>
|
||||||
|
<TopNavigation title='Dina barn' alignment='center' accessoryLeft={BackAction} />
|
||||||
|
<Divider/>
|
||||||
|
<Layout style={{ flex: 1}} level='1'>
|
||||||
|
<List
|
||||||
|
style={styles.container}
|
||||||
|
contentContainerStyle={styles.contentContainer}
|
||||||
|
data={children}
|
||||||
|
renderItem={renderItem} />
|
||||||
|
</Layout>
|
||||||
|
</SafeAreaView>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
topContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
flex: 1,
|
||||||
|
margin: 10
|
||||||
|
},
|
||||||
|
itemDescription: {
|
||||||
|
zIndex: 1,
|
||||||
|
marginVertical: 16
|
||||||
|
},
|
||||||
|
itemFooter: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
paddingHorizontal: 12
|
||||||
|
},
|
||||||
|
iconButton: {
|
||||||
|
paddingHorizontal: 0
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,33 @@
|
||||||
|
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';
|
||||||
|
|
||||||
|
export const Classmates = ({classmates}) => {
|
||||||
|
|
||||||
|
const renderItemIcon = (props) => <Icon {...props} name={'people-outline'}/>
|
||||||
|
|
||||||
|
const renderItem = ({ item }) => (
|
||||||
|
<ListItem
|
||||||
|
title={`${item.firstname} ${item.lastname}`}
|
||||||
|
description={item.guardians.map(guardian => `${guardian.firstname} ${guardian.lastname}`).join(', ')}
|
||||||
|
accessoryLeft={renderItemIcon}
|
||||||
|
accessoryRight={(props) => ContactMenu({...props, contact: item})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List
|
||||||
|
style={styles.container}
|
||||||
|
data={classmates}
|
||||||
|
ItemSeparatorComponent={Divider}
|
||||||
|
renderItem={renderItem}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
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'
|
||||||
|
|
||||||
|
|
||||||
|
export const ContactMenu = ({contact}) => {
|
||||||
|
|
||||||
|
const [visible, setVisible] = React.useState(false);
|
||||||
|
const [selectedTitle, setSelectedTitle] = React.useState('No items selected');
|
||||||
|
|
||||||
|
const contactIcon = (props) => <Icon {...props} name={'phone-outline'}/>
|
||||||
|
const renderToggleButton = () => (
|
||||||
|
<Button onPress={() => setVisible(true)} appearance='ghost' accessoryLeft={contactIcon}>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const CallIcon = (props) => <Icon {...props} name='phone-outline'/>
|
||||||
|
const SMSIcon = (props) => <Icon {...props} name='message-square-outline'/>
|
||||||
|
const EmailIcon = (props) => <Icon {...props} name='email-outline'/>
|
||||||
|
const MapIcon = (props) => <Icon {...props} name='map-outline'/>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverflowMenu
|
||||||
|
visible={visible}
|
||||||
|
anchor={renderToggleButton}
|
||||||
|
onBackdropPress={() => setVisible(false)}>
|
||||||
|
{contact.guardians.map((parent, i) =>
|
||||||
|
<MenuGroup key={i} title={`${parent.firstname} ${parent.lastname}`}>
|
||||||
|
<MenuItem accessoryLeft={CallIcon} visible={!parent.mobile} title={`Ring`} onPress={e => Linking.openURL(`tel:${parent.mobile}`)}/>
|
||||||
|
<MenuItem accessoryLeft={SMSIcon} visible={!parent.mobile} title={`SMS`} onPress={e => Linking.openURL(`sms:${parent.mobile}`)}/>
|
||||||
|
<MenuItem accessoryLeft={EmailIcon} visible={!parent.email} title={`Maila`} onPress={e => Linking.openURL(`mailto:${parent.email}`)}/>
|
||||||
|
<MenuItem accessoryLeft={MapIcon} visible={!parent.address} title={`Hem`} onPress={e => Linking.openURL(`http://maps.apple.com/?daddr=${parent.address}`)}/>
|
||||||
|
</MenuGroup>
|
||||||
|
)}
|
||||||
|
</OverflowMenu>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { SafeAreaView } from 'react-native';
|
||||||
|
import { Button, Divider, Layout, TopNavigation } from '@ui-kitten/components';
|
||||||
|
|
||||||
|
export const Login = ({ navigation }) => {
|
||||||
|
|
||||||
|
const navigateDetails = () => {
|
||||||
|
navigation.navigate('Children');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={{ flex: 1 }}>
|
||||||
|
<TopNavigation title='Skolplattformen' alignment='center'/>
|
||||||
|
<Divider/>
|
||||||
|
<Layout style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
<Button onPress={navigateDetails}>Login</Button>
|
||||||
|
</Layout>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
|
import { Login } from './login.component';
|
||||||
|
import { Children } from './children.component';
|
||||||
|
import { Child } from './child.component';
|
||||||
|
|
||||||
|
const { Navigator, Screen } = createStackNavigator();
|
||||||
|
|
||||||
|
const HomeNavigator = () => (
|
||||||
|
<Navigator headerMode='none'>
|
||||||
|
<Screen name='Login' component={Login}/>
|
||||||
|
<Screen name='Children' component={Children}/>
|
||||||
|
<Screen name='Child' component={Child}/>
|
||||||
|
</Navigator>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AppNavigator = (children) => (
|
||||||
|
<NavigationContainer>
|
||||||
|
<HomeNavigator/>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
import { Card, List, Text } from '@ui-kitten/components'
|
import { Card, List, Text, Layout } from '@ui-kitten/components'
|
||||||
import Markdown from 'react-native-markdown-display'
|
import Markdown from 'react-native-markdown-display'
|
||||||
import { Image } from 'react-native-svg'
|
import { Image } from 'react-native-svg'
|
||||||
|
|
||||||
|
@ -8,25 +8,16 @@ import { Image } from 'react-native-svg'
|
||||||
export const NewsList = ({news}) => {
|
export const NewsList = ({news}) => {
|
||||||
|
|
||||||
const renderItemHeader = (headerProps, info) => (
|
const renderItemHeader = (headerProps, info) => (
|
||||||
<View {...headerProps} style={styles.header}>
|
<View {...headerProps} >
|
||||||
<Text category='h6' style={styles.headerText}>
|
<Text category='h6'>{info.item.header}</Text>
|
||||||
{info.item.header}
|
<Text category='s1'>By Wikipedia</Text>
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
||||||
const renderItemFooter = (footerProps, info) => (
|
|
||||||
<Text {...footerProps}>
|
|
||||||
Publicerad i Skolplattformen
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
|
|
||||||
const renderItem = (info) => (
|
const renderItem = (info) => (
|
||||||
<Card
|
<Card
|
||||||
style={styles.item}
|
style={styles.card}
|
||||||
status='basic'
|
header={headerProps => renderItemHeader(headerProps, info)}>
|
||||||
header={headerProps => renderItemHeader(headerProps, info)}
|
|
||||||
footer={footerProps => renderItemFooter(footerProps, info)}>
|
|
||||||
<Markdown style={{ body: {color: 'black', fontSize: 15}, heading1: {color: 'black'} }}>
|
<Markdown style={{ body: {color: 'black', fontSize: 15}, heading1: {color: 'black'} }}>
|
||||||
{decodeURIComponent(info.item.body)}
|
{decodeURIComponent(info.item.body)}
|
||||||
</Markdown>
|
</Markdown>
|
||||||
|
@ -34,33 +25,24 @@ export const NewsList = ({news}) => {
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<Layout style={styles.topContainer} level='1'>
|
||||||
style={styles.container}
|
<List
|
||||||
contentContainerStyle={styles.contentContainer}
|
style={styles.container}
|
||||||
data={news}
|
contentContainerStyle={styles.contentContainer}
|
||||||
renderItem={renderItem} />
|
data={news}
|
||||||
|
renderItem={renderItem} />
|
||||||
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
header: {
|
topContainer: {
|
||||||
backgroundColor: '#fff',
|
flexDirection: 'row',
|
||||||
minHeight: 30,
|
justifyContent: 'space-between',
|
||||||
padding: 25
|
|
||||||
},
|
},
|
||||||
headerText: {
|
card: {
|
||||||
color: '#000'
|
flex: 1,
|
||||||
|
margin: 2,
|
||||||
},
|
},
|
||||||
container: {
|
});
|
||||||
maxHeight: '100%'
|
|
||||||
},
|
|
||||||
contentContainer: {
|
|
||||||
paddingVertical: 4
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
marginVertical: 4
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
backgroundColor: '#000'
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -1,36 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
|
||||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
|
||||||
import { TabBar, Tab, Layout, Text } from '@ui-kitten/components';
|
|
||||||
import { ChildList } from './childList.component';
|
|
||||||
import { DetailsScreen } from './details.component';
|
|
||||||
|
|
||||||
const { Navigator, Screen } = createMaterialTopTabNavigator();
|
|
||||||
|
|
||||||
const ChildScreen = ({data}) => (
|
|
||||||
<Layout style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
||||||
<Text category='h1'>Nyheter</Text>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
|
|
||||||
const TopTabBar = ({ navigation, state }) => (
|
|
||||||
<TabBar
|
|
||||||
selectedIndex={state.index}
|
|
||||||
onSelect={index => navigation.navigate(state.routeNames[index])}>
|
|
||||||
<Tab title='Nyheter'/>
|
|
||||||
<Tab title='Klassen'/>
|
|
||||||
</TabBar>
|
|
||||||
);
|
|
||||||
|
|
||||||
const TabNavigator = ({children}) => (
|
|
||||||
<Navigator tabBar={props => <TopTabBar {...props} />}>
|
|
||||||
<Screen name='Child' component={ChildScreen} data={children}/>
|
|
||||||
<Screen name='Class' component={DetailsScreen}/>
|
|
||||||
</Navigator>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const AppNavigator = ({children}) => (
|
|
||||||
<NavigationContainer>
|
|
||||||
<TabNavigator children={children }/>
|
|
||||||
</NavigationContainer>
|
|
||||||
);
|
|
|
@ -1591,6 +1591,11 @@
|
||||||
"integrity": "sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ==",
|
"integrity": "sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@react-native-community/masked-view": {
|
||||||
|
"version": "0.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-native-community/masked-view/-/masked-view-0.1.10.tgz",
|
||||||
|
"integrity": "sha512-rk4sWFsmtOw8oyx8SD3KSvawwaK7gRBSEIy2TAwURyGt+3TizssXP1r8nx3zY+R7v2vYYHXZ+k2/GULAT/bcaQ=="
|
||||||
|
},
|
||||||
"@react-navigation/core": {
|
"@react-navigation/core": {
|
||||||
"version": "5.14.4",
|
"version": "5.14.4",
|
||||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.14.4.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.14.4.tgz",
|
||||||
|
@ -1643,6 +1648,15 @@
|
||||||
"nanoid": "^3.1.15"
|
"nanoid": "^3.1.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@react-navigation/stack": {
|
||||||
|
"version": "5.12.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-5.12.8.tgz",
|
||||||
|
"integrity": "sha512-wUJFbU0v606RBXOUxHToCXJNmiwxtFYhN2TFvjxCZ3PJU+OWWx8HTmn99pT3rVH4Ax2cfO5BDUy9v+r74ZrIWw==",
|
||||||
|
"requires": {
|
||||||
|
"color": "^3.1.3",
|
||||||
|
"react-native-iphone-x-helper": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/babel__core": {
|
"@types/babel__core": {
|
||||||
"version": "7.1.12",
|
"version": "7.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz",
|
||||||
|
@ -8979,6 +8993,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-native-iphone-x-helper": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg=="
|
||||||
|
},
|
||||||
|
"react-native-maps": {
|
||||||
|
"version": "0.27.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-0.27.1.tgz",
|
||||||
|
"integrity": "sha512-HygBkZBecTnIVRYrSiLRAvu4OmXOYso/A7c6Cy73HkOh9CgGV8Ap5eBea24tvmFGptjj5Hg8AJ94/YbmWK1Okw=="
|
||||||
|
},
|
||||||
"react-native-markdown-display": {
|
"react-native-markdown-display": {
|
||||||
"version": "7.0.0-alpha.2",
|
"version": "7.0.0-alpha.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-markdown-display/-/react-native-markdown-display-7.0.0-alpha.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-markdown-display/-/react-native-markdown-display-7.0.0-alpha.2.tgz",
|
||||||
|
|
|
@ -12,14 +12,17 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eva-design/eva": "2.0.0",
|
"@eva-design/eva": "2.0.0",
|
||||||
"@eva-design/material": "^2.0.0",
|
"@eva-design/material": "^2.0.0",
|
||||||
|
"@react-native-community/masked-view": "^0.1.10",
|
||||||
"@react-navigation/material-top-tabs": "^5.3.10",
|
"@react-navigation/material-top-tabs": "^5.3.10",
|
||||||
"@react-navigation/native": "^5.8.10",
|
"@react-navigation/native": "^5.8.10",
|
||||||
|
"@react-navigation/stack": "^5.12.8",
|
||||||
"@ui-kitten/components": "5.0.0",
|
"@ui-kitten/components": "5.0.0",
|
||||||
"@ui-kitten/eva-icons": "5.0.0",
|
"@ui-kitten/eva-icons": "5.0.0",
|
||||||
"react": "16.11.0",
|
"react": "16.11.0",
|
||||||
"react-native": "0.62.2",
|
"react-native": "0.62.2",
|
||||||
"react-native-calendar-strip": "^2.0.9",
|
"react-native-calendar-strip": "^2.0.9",
|
||||||
"react-native-gesture-handler": "^1.9.0",
|
"react-native-gesture-handler": "^1.9.0",
|
||||||
|
"react-native-maps": "^0.27.1",
|
||||||
"react-native-markdown-display": "^7.0.0-alpha.2",
|
"react-native-markdown-display": "^7.0.0-alpha.2",
|
||||||
"react-native-reanimated": "^1.13.2",
|
"react-native-reanimated": "^1.13.2",
|
||||||
"react-native-safe-area-context": "^3.1.9",
|
"react-native-safe-area-context": "^3.1.9",
|
||||||
|
|
Loading…
Reference in New Issue