feat: 🎸 Den nygamla klasslistan (#462)

* feat: 🎸 Den nygamla klasslistan

Börjar lägga tillbaka klasslistan och funktionalitet kring den

 Closes: #441

* feat: 🎸 Barnets klass och skola under namnet

Försöker få fram namnet på klassen från klasslistan om det finns och
namnet på skolan från Skola24 om det finna schema

* fix: 🐛 Lade till språkstöd (svenska,engelska) till klasslistan

* test: 💍 Tester fixade och tillgada

* style: 💄 Linting
This commit is contained in:
Kajetan Kazimierczak 2021-09-16 10:28:36 +02:00 committed by GitHub
parent a480cbc48a
commit f0d05a5000
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 144 additions and 29 deletions

View File

@ -7,6 +7,7 @@ import {
useSchedule,
useMenu,
useTimetable,
useClassmates,
} from '@skolplattformen/api-hooks'
import { render } from '../../utils/testHelpers'
import React from 'react'
@ -37,6 +38,7 @@ beforeEach(() => {
useSchedule.mockReturnValueOnce({ data: [], status: 'loaded' })
useMenu.mockReturnValueOnce({ data: [], status: 'loaded' })
useTimetable.mockReturnValueOnce({ data: [], status: 'loaded' })
useClassmates.mockReturnValueOnce({ data: [], status: 'loaded' })
useNavigation.mockReturnValue({ navigate: jest.fn(), setOptions: jest.fn() })
})
@ -156,6 +158,33 @@ test('renders multiple children', () => {
).toBeTruthy()
})
test('renders child in class', () => {
useChildList.mockImplementationOnce(() => ({
data: [
{
name: 'Test Testsson',
status: 'G',
schoolID: 'Vallaskolan',
},
],
status: 'loaded',
}))
useClassmates.mockReset()
useClassmates.mockImplementationOnce(() => ({
data: [
{
className: '8C',
},
],
status: 'loaded',
}))
const screen = setup()
expect(screen.getByText('Test Testsson')).toBeTruthy()
expect(screen.getByText('8C • Vallaskolan')).toBeTruthy()
})
test('removes any parenthesis from name', () => {
useChildList.mockImplementationOnce(() => ({
data: [

View File

@ -20,6 +20,7 @@ import { RootStackParamList } from './navigation.component'
import { NavigationTitle } from './navigationTitle.component'
import { NewsList } from './newsList.component'
import { NotificationsList } from './notificationsList.component'
import { Classmates } from './classmates.component'
import { TabBarLabel } from './tabBarLabel.component'
type ChildNavigationProp = StackNavigationProp<RootStackParamList, 'Child'>
@ -30,6 +31,7 @@ export type ChildTabParamList = {
Notifications: undefined
Calendar: undefined
Menu: undefined
Classmates: undefined
}
interface TabTitleProps {
@ -43,6 +45,7 @@ const NewsScreen = () => <NewsList />
const NotificationsScreen = () => <NotificationsList />
const CalendarScreen = () => <Calendar />
const MenuScreen = () => <Menu />
const ClassmatesScreen = () => <Classmates />
const TabNavigator = ({
initialRouteName = 'News',
@ -67,6 +70,8 @@ const TabNavigator = ({
iconName = focused ? 'calendar' : 'calendar-outline'
else if (route.name === 'Menu')
iconName = focused ? 'clipboard' : 'clipboard-outline'
else if (route.name === 'Classmates')
iconName = focused ? 'people' : 'people-outline'
return <Icon name={iconName} fill={color} height={24} width={24} />
},
}
@ -92,6 +97,11 @@ const TabNavigator = ({
component={MenuScreen}
options={{ title: translate('navigation.menu') }}
/>
<Screen
name="Classmates"
component={ClassmatesScreen}
options={{ title: translate('navigation.classmates') }}
/>
</Navigator>
)
@ -107,6 +117,8 @@ const getHeaderTitle = (route: any) => {
return translate('navigation.calender')
case 'Menu':
return translate('navigation.menu')
case 'Classmates':
return translate('navigation.classmates')
}
}

View File

@ -3,6 +3,7 @@ import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import {
useCalendar,
useClassmates,
useMenu,
useNews,
useNotifications,
@ -42,6 +43,7 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
const navigation = useNavigation<ChildListItemNavigationProp>()
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(
@ -75,6 +77,16 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
}
const getClassName = () => {
// hack: we can find the class name (ex. 8C) from the classmates.
// let's pick the first one and select theirs class
// hack 2: we can find school namn in skola24 if child data is there
if (classmates.length > 0) {
return (
classmates[0].className +
(child.schoolID == null ? '' : ' • ' + child.schoolID)
)
}
// Taken from Skolverket
// https://www.skolverket.se/skolutveckling/anordna-och-administrera-utbildning/administrera-utbildning/skoltermer-pa-engelska
const abbrevations = {

View File

@ -1,25 +1,66 @@
import { Card, Text } from '@ui-kitten/components'
import React from 'react'
import { View, StyleSheet } from 'react-native'
import { StyleSheet, ListRenderItemInfo } from 'react-native'
import {
Divider,
List,
ListItem,
Icon,
IconProps,
Text,
} from '@ui-kitten/components'
import { fullName, guardians, sortByFirstName } from '../utils/peopleHelpers'
import { useChild } from './childContext.component'
import { useClassmates } from '@skolplattformen/api-hooks'
import { ContactMenu } from './contactMenu.component'
import { Classmate } from '@skolplattformen/embedded-api'
import { translate } from '../utils/translation'
interface ClassmatesProps {
setSelected: (value?: number | null) => void
}
export const Classmates = () => {
const cardHeader = () => {
return (
<View style={styles.topContainer}>
<Text category="h6">Klasslistan ej tillgänglig</Text>
</View>
)
}
const child = useChild()
const { data } = useClassmates(child)
const renderItemIcon = (props: IconProps) => (
<Icon {...props} name="people-outline" />
)
const [selected, setSelected] = React.useState()
const renderItem = ({ item, index }: ListRenderItemInfo<Classmate>) => (
<ListItem
accessibilityLabel={`${translate('classmates.child')} ${index + 1}`}
accessibilityHint={`${translate(
'classmates.contactsForGuardianFor'
)} ${fullName(item)}`}
title={fullName(item)}
onPress={() => setSelected(item)}
description={guardians(item.guardians)}
accessoryLeft={renderItemIcon}
accessoryRight={() => (
<ContactMenu
contact={item}
selected={item === selected}
setSelected={setSelected}
/>
)}
/>
)
return (
<View style={styles.container}>
<Card header={cardHeader} style={styles.contentContainer}>
<Text>
Klasslista kan tyvärr inte visas längre. Vi jobbar att lösa det,
och återkommer med information när vi vet mer.
<List
style={styles.container}
data={sortByFirstName(data)}
ItemSeparatorComponent={Divider}
ListHeaderComponent={
<Text category="h5" style={styles.listHeader}>
{data?.length
? `${translate('classmates.class')} ${data[0].className}`
: translate('classmates.class')}
</Text>
</Card>
</View>
}
renderItem={renderItem}
contentContainerStyle={styles.contentContainer}
/>
)
}
@ -38,7 +79,6 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
},
listHeader: {
backgroundColor: '#fff',
paddingTop: 10,
paddingLeft: 15,
},

View File

@ -77,34 +77,34 @@ export const ContactMenu = ({
>
<MenuItem
testID="CallMenuItem"
accessibilityLabel="Ring"
accessibilityLabel={translate('contact.call')}
accessoryLeft={CallIcon}
style={{ display: shouldDisplay(mobile) }}
title="Ring"
title={translate('contact.call')}
onPress={() => Linking.openURL(`tel:${mobile}`)}
/>
<MenuItem
testID="SMSMenuItem"
accessibilityLabel="SMS"
accessibilityLabel={translate('contact.sms')}
accessoryLeft={SMSIcon}
style={{ display: shouldDisplay(mobile) }}
title="SMS"
title={translate('contact.sms')}
onPress={() => Linking.openURL(`sms:${mobile}`)}
/>
<MenuItem
testID="SendEmailMenuItem"
accessibilityLabel="Maila"
accessibilityLabel={translate('contact.email')}
accessoryLeft={EmailIcon}
style={{ display: shouldDisplay(email) }}
title="Maila"
title={translate('contact.email')}
onPress={() => Linking.openURL(`mailto:${email}`)}
/>
<MenuItem
testID="ShowHomeMenuItem"
accessibilityLabel="Hem"
accessibilityLabel={translate('contact.home')}
accessoryLeft={MapIcon}
style={{ display: shouldDisplay(address) }}
title="Hem"
title={translate('contact.home')}
onPress={() =>
Linking.openURL(`http://maps.apple.com/?daddr=${address}`)
}

View File

@ -90,7 +90,8 @@
"calender": "Calendar",
"menu": "Menu",
"news": "News",
"notifications": "Notifications"
"notifications": "Notifications",
"classmates": "Classmates"
},
"news": {
"backToChild": "Back to child",
@ -112,7 +113,17 @@
"lunch": "Lunch",
"gymBag": "Gym bag"
},
"classmates": {
"class": "Class",
"child": "Child",
"contactsForGuardiansFor": "Contact information for guardians for"
},
"contact": {
"a11y_show_contact_info_button_hint": "Show contact info"
"a11y_show_contact_info_button_hint": "Shows contact information",
"a11y_show_contact_info_button_label": "Show contant information",
"call": "Call",
"sms": "SMS",
"email": "E-mail",
"home": "Home"
}
}

View File

@ -90,7 +90,8 @@
"calender": "Kalender",
"menu": "Matsedel",
"news": "Nyheter",
"notifications": "Aviseringar"
"notifications": "Aviseringar",
"classmates": "Klassen"
},
"news": {
"backToChild": "Tillbaka till barn",
@ -112,7 +113,17 @@
"lunch": "Lunch",
"gymBag": "Gympapåse"
},
"classmates": {
"class": "Klass",
"child": "Barn",
"contactsForGuardiansFor": "Kontaktuppgifter för vårdnadshavare till"
},
"contact": {
"a11y_show_contact_info_button_hint": "Visa kontaktinfo"
"a11y_show_contact_info_button_hint": "Visar kontaktinformation",
"a11y_show_contact_info_button_label": "Visa kontaktinformation",
"call": "Ring",
"sms": "SMS",
"email": "Maila",
"home": "Hem"
}
}