chore: merge yarn.lock with main

This commit is contained in:
Christian Landgren 2021-08-16 23:45:56 +02:00
commit 038680803b
93 changed files with 1585 additions and 1383 deletions

View File

@ -1,20 +1,20 @@
import React from 'react'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import * as eva from '@eva-design/eva'
import AsyncStorage from '@react-native-async-storage/async-storage'
import CookieManager from '@react-native-community/cookies'
import { ApiProvider } from '@skolplattformen/api-hooks'
import init from '@skolplattformen/embedded-api'
import { ApplicationProvider, IconRegistry } from '@ui-kitten/components'
import { EvaIconsPack } from '@ui-kitten/eva-icons'
import * as eva from '@eva-design/eva'
import darkTheme from './design/dark.json'
import lightTheme from './design/light.json'
import { AppNavigator } from './components/navigation.component'
import init from '@skolplattformen/embedded-api'
import { ApiProvider } from '@skolplattformen/api-hooks'
import CookieManager from '@react-native-community/cookies'
import AsyncStorage from '@react-native-async-storage/async-storage'
import React from 'react'
import { StatusBar } from 'react-native'
import { useBackgroundBlur } from './utils/blur'
import { LanguageProvider } from './context/language/languageContext'
import { translations } from './utils/translation'
import { AppearanceProvider, useColorScheme } from 'react-native-appearance'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { AppNavigator } from './components/navigation.component'
import { LanguageProvider } from './context/language/languageContext'
import { default as customMapping } from './design/mapping.json'
import { darkTheme, lightTheme } from './design/themes'
import { useBackgroundBlur } from './utils/blur'
import { translations } from './utils/translation'
const api = init(fetch, CookieManager)
const reporter = __DEV__
@ -43,10 +43,8 @@ export default () => {
<IconRegistry icons={EvaIconsPack} />
<ApplicationProvider
{...eva}
theme={{
...(colorScheme === 'dark' ? eva.dark : eva.light),
...(colorScheme === 'dark' ? darkTheme : lightTheme),
}}
customMapping={customMapping}
theme={colorScheme === 'dark' ? darkTheme : lightTheme}
>
<LanguageProvider cache={true} data={translations}>
<AppNavigator />

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Lager_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
<g>
<path fill="#479CBE" d="M241.9,423.6l13.2-83.2c-5.2,0-14.1,0-14.1,0c-6.6,0-15.1-3.7-17.6-10.5c-0.8-2.3-2.7-10.2,8.2-17.9
c3.9-2.7,6.4-5.7,6.9-8c0.5-2.4-0.1-4.5-1.8-6.1c-2.4-2.3-7.1-3.6-13.1-3.6c-10.1,0-17.2,5.8-17.9,10c-0.5,3.1,1.9,5.6,4,7.2
c6.3,4.7,7.8,11.5,3.9,17.9c-4,6.6-12.7,10.9-22,11c0,0-9.2,0-14.4,0c-1.2,8.1-20.8,132.3-22.3,142.1h78.1
c0.7-4.4,4.3-27.9,9.2-58.9H241.9z"/>
<path fill="#00A5C3" d="M346.5,267.6H267l-10.6,67.3l13.5,0c7.4,0,14.4-3.4,17.4-8.3c1-1.6,1.4-3,1.4-4.3c0-2.8-1.9-4.9-3.8-6.3
c-5.2-3.9-6.3-8-6.3-10.9c0-0.6,0-1.1,0.1-1.6c1.1-7.1,10.7-14.8,23.4-14.8c7.6,0,13.4,1.8,16.9,5.1c3.1,2.9,4.3,7,3.4,11.3
c-1.1,5.1-6.2,9.3-9.1,11.4c-7.7,5.4-6.7,10.1-6.2,11.5c1.6,4.2,7.7,6.9,12.4,6.9H340c0,0,0,0,0,0.1c28,0.2,43,13.1,38.3,43.1
c-4.4,27.9-25.8,39.9-51.3,40.1l-10.1,64.4h14.9c62.9,0,114.3-40.4,124.4-104.2C468.7,299.2,418.5,267.6,346.5,267.6z"/>
<path fill="#235971" d="M346.5,267.6H267l-10.6,67.3l13.5,0c7.4,0,14.4-3.4,17.4-8.3c1-1.6,1.4-3,1.4-4.3c0-2.8-1.9-4.9-3.8-6.3
c-5.2-3.9-6.3-8-6.3-10.9c0-0.6,0-1.1,0.1-1.6c1.1-7.1,10.7-14.8,23.4-14.8c7.6,0,13.4,1.8,16.9,5.1c3.1,2.9,4.3,7,3.4,11.3
c-1.1,5.1-6.2,9.3-9.1,11.4c-7.7,5.4-6.7,10.1-6.2,11.5c1.6,4.2,7.7,6.9,12.4,6.9H340c0,0,0,0,0,0.1c28,0.2,43,13.1,38.3,43.1
c-4.4,27.9-25.8,39.9-51.3,40.1l-10.1,64.4h14.9c62.9,0,114.3-40.4,124.4-104.2C468.7,299.2,418.5,267.6,346.5,267.6z"/>
<g>
<path fill="#235971" d="M150.7,511.2h31.9c13.6,0,16.9,6.9,15.9,13.2c-0.8,5.1-4.3,8.9-10.3,11.4c7.6,2.9,10.6,7.4,9.5,14.5
c-1.4,8.9-9.1,15.5-19.2,15.5h-36.3L150.7,511.2z M171.8,533.8c6.2,0,9.1-3.3,9.7-7.2c0.6-4.2-1.3-7.1-7.5-7.1h-5.5l-2.2,14.3
H171.8z M168.4,557.4c6.4,0,10.1-2.6,11-7.9c0.7-4.6-1.9-7.3-8.1-7.3H165l-2.4,15.3H168.4z"/>
<path fill="#235971" d="M242.4,566.2c-8.3,0.6-12.3-0.3-14.3-3.9c-4.4,2.7-9.3,4.1-14.5,4.1c-9.4,0-12.7-4.9-11.8-10.3
c0.4-2.6,1.9-5.1,4.3-7.2c5.2-4.5,18-5.1,23-8.5c0.4-3.8-1.1-5.2-5.8-5.2c-5.5,0-10.1,1.8-18,7.2l1.9-12.4
c6.8-4.9,13.4-7.2,21-7.2c9.7,0,18.3,4,16.7,14.6l-1.9,12c-0.7,4.2-0.5,5.5,4.2,5.6L242.4,566.2z M228,547.4
c-4.4,2.8-12.6,2.3-13.5,8.1c-0.4,2.7,1.3,4.7,4,4.7c2.6,0,5.8-1.1,8.4-2.9c-0.2-1-0.1-2,0.2-3.9L228,547.4z"/>
<path fill="#235971" d="M257.9,523.5h16.6l-0.9,5.5c5.3-4.5,9.3-6.2,14.5-6.2c9.3,0,13.6,5.7,12.1,15l-4.3,27.9h-16.6l3.6-23.1
c0.7-4.2-0.6-6.2-3.8-6.2c-2.6,0-5,1.4-7.3,4.5l-3.8,24.7h-16.6L257.9,523.5z"/>
<path fill="#235971" d="M313.1,511.2h16.6l-4.2,26.8l15.9-14.5h20.5l-20.4,18l16.4,24.2h-20.9l-12.6-19.5h-0.2l-3,19.5h-16.6
L313.1,511.2z"/>
</g>
<g>
<path fill="#479CBE" d="M371.9,511.2H391l-8.4,54.5h-19.1L371.9,511.2z"/>
<path fill="#479CBE" d="M400.3,511.2h27.3c21.1,0,27.2,15.3,25.2,28c-1.9,12.4-11.7,26.5-30.2,26.5h-30.8L400.3,511.2z M418,552.7
c9.3,0,14.4-4.6,15.9-14.3c1.1-7.2-1.1-14.3-11.4-14.3h-5.1l-4.4,28.6H418z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,93 @@
Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -37,12 +37,6 @@ beforeEach(() => {
AsyncStorage.clear()
})
test('renders title', () => {
const screen = setup()
expect(screen.getByText('Anmäl frånvaro')).toBeTruthy()
})
test('can fill out the form with full day absence', async () => {
const screen = setup()

View File

@ -1,8 +1,7 @@
import { useApi, useNewsDetails } from '@skolplattformen/api-hooks'
import React from 'react'
import { render } from '../../utils/testHelpers'
import { NewsItem } from '../newsItem.component'
import { fireEvent } from '@testing-library/react-native'
import { useNewsDetails, useApi } from '@skolplattformen/api-hooks'
jest.mock('@skolplattformen/api-hooks')
@ -89,11 +88,3 @@ test('renders an article without modified date if date is invalid', () => {
expect(screen.getByText('Publicerad: 15 feb 2021 10:13')).toBeTruthy()
expect(screen.queryByText('Uppdaterad: Invalid DateTime')).toBeFalsy()
})
test('handles navigating back to child view', () => {
const screen = setup()
fireEvent.press(screen.getByTestId('topNavBackToChild'))
expect(navigation.goBack).toHaveBeenCalled()
})

View File

@ -1,35 +1,29 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { RouteProp, useRoute } from '@react-navigation/native'
import {
Button,
CheckBox,
Divider,
Input,
Layout,
StyleService,
Text,
TopNavigation,
TopNavigationAction,
useStyleSheet,
} from '@ui-kitten/components'
import { Formik } from 'formik'
import moment from 'moment'
import Personnummer from 'personnummer'
import React from 'react'
import React, { useCallback } from 'react'
import { View } from 'react-native'
import DateTimePickerModal from 'react-native-modal-datetime-picker'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import * as Yup from 'yup'
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
import { SafeAreaView } from '../ui/safeAreaView.component'
import { studentName } from '../utils/peopleHelpers'
import { useSMS } from '../utils/SMS'
import { translate } from '../utils/translation'
import { BackIcon, AlertIcon } from './icon.component'
import { AlertIcon } from './icon.component'
import { RootStackParamList } from './navigation.component'
import { SafeAreaViewContainer } from '../ui/safeAreaViewContainer.component'
import { NavigationTitle } from './navigationTitle.component'
type AbsenceNavigationProp = StackNavigationProp<RootStackParamList, 'Absence'>
type AbsenceRouteProps = RouteProp<RootStackParamList, 'Absence'>
interface AbsenceFormValues {
@ -41,7 +35,21 @@ interface AbsenceFormValues {
endTime: moment.Moment
}
const Alert = (props: any) => <AlertIcon {...props} />
export const absenceRouteOptions = ({
route,
}: {
route: RouteProp<RootStackParamList, 'Absence'>
}): NativeStackNavigationOptions => {
const child = route.params.child
return {
headerCenter: () => (
<NavigationTitle
title={translate('abscense.title')}
subtitle={studentName(child?.name)}
/>
),
}
}
const Absence = () => {
const AbsenceSchema = Yup.object().shape({
@ -52,7 +60,7 @@ const Absence = () => {
),
isFullDay: Yup.bool().required(),
})
const navigation = useNavigation<AbsenceNavigationProp>()
const route = useRoute<AbsenceRouteProps>()
const { sendSMS } = useSMS()
const { child } = route.params
@ -61,6 +69,28 @@ const Absence = () => {
const maximumDate = moment().hours(17).minute(0)
const styles = useStyleSheet(themedStyles)
const submit = useCallback(
async (values: AbsenceFormValues) => {
const ssn = Personnummer.parse(values.socialSecurityNumber).format()
if (values.isFullDay) {
sendSMS(ssn)
} else {
sendSMS(
`${ssn} ${moment(values.startTime).format('HHmm')}-${moment(
values.endTime
).format('HHmm')}`
)
}
await AsyncStorage.setItem(
`@childssn.${child.id}`,
values.socialSecurityNumber
)
},
[child.id, sendSMS]
)
React.useEffect(() => {
const getSocialSecurityNumber = async () => {
const ssn = await AsyncStorage.getItem(`@childssn.${child.id}`)
@ -80,210 +110,155 @@ const Absence = () => {
}
return (
<SafeAreaView>
<SafeAreaViewContainer>
<TopNavigation
accessoryLeft={() => (
<TopNavigationAction
icon={BackIcon}
onPress={() => navigation.goBack()}
/>
)}
alignment="center"
style={styles.topBar}
title={() => (
<Text maxFontSizeMultiplier={1.5} style={styles.topNavigationTitle}>
{translate('abscense.title')}
</Text>
)}
subtitle={() => (
<Text
maxFontSizeMultiplier={1.5}
style={styles.topNavigationSubtitle}
>
{studentName(child.name)}
</Text>
)}
/>
<Divider />
<Layout style={styles.wrap}>
<Formik
enableReinitialize
validationSchema={AbsenceSchema}
initialValues={initialValues}
onSubmit={async (values) => {
const ssn = Personnummer.parse(
values.socialSecurityNumber
).format()
<Formik
enableReinitialize
validationSchema={AbsenceSchema}
initialValues={initialValues}
onSubmit={submit}
>
{({
handleChange,
handleBlur,
handleSubmit,
setFieldValue,
values,
touched,
errors,
}) => {
const hasError = (field: keyof typeof values) =>
errors[field] && touched[field]
if (values.isFullDay) {
sendSMS(ssn)
} else {
sendSMS(
`${ssn} ${moment(values.startTime).format('HHmm')}-${moment(
values.endTime
).format('HHmm')}`
)
}
await AsyncStorage.setItem(
`@childssn.${child.id}`,
values.socialSecurityNumber
)
}}
>
{({
handleChange,
handleBlur,
handleSubmit,
setFieldValue,
values,
touched,
errors,
}) => {
const hasError = (field: keyof typeof values) =>
errors[field] && touched[field]
return (
<View>
<View style={styles.field}>
<Text style={styles.label}>
{translate('general.socialSecurityNumber')}
</Text>
<Input
testID="socialSecurityNumberInput"
keyboardType="number-pad"
onChangeText={handleChange('socialSecurityNumber')}
onBlur={handleBlur('socialSecurityNumber')}
status={
hasError('socialSecurityNumber') ? 'danger' : 'basic'
}
value={values.socialSecurityNumber}
accessoryRight={
errors.socialSecurityNumber ? Alert : undefined
}
/>
{hasError('socialSecurityNumber') && (
<Text style={styles.error}>
{errors.socialSecurityNumber}
</Text>
)}
</View>
<View style={styles.field}>
<CheckBox
checked={values.isFullDay}
onChange={(checked) =>
setFieldValue('isFullDay', checked)
}
>
{translate('abscense.entireDay')}
</CheckBox>
</View>
{!values.isFullDay && (
<View style={styles.partOfDay}>
<View style={styles.inputHalf}>
<Text style={styles.label}>
{translate('abscense.startTime')}
</Text>
<Button
status="basic"
onPress={() =>
setFieldValue('displayStartTimePicker', true)
}
>
{moment(values.startTime).format('LT')}
</Button>
<DateTimePickerModal
cancelTextIOS={translate('general.cancel')}
confirmTextIOS={translate('general.confirm')}
date={moment(values.startTime).toDate()}
isVisible={values.displayStartTimePicker}
headerTextIOS={translate(
'abscense.selectAbscenseStartTime'
)}
locale="sv-SE"
maximumDate={maximumDate.toDate()}
minimumDate={minumumDate.toDate()}
minuteInterval={10}
mode="time"
onConfirm={(date) => {
setFieldValue('startTime', date)
setFieldValue('displayStartTimePicker', false)
}}
onCancel={() =>
setFieldValue('displayStartTimePicker', false)
}
/>
</View>
<View style={styles.spacer} />
<View style={styles.inputHalf}>
<Text style={styles.label}>
{translate('abscense.endTime')}
</Text>
<Button
status="basic"
onPress={() =>
setFieldValue('displayEndTimePicker', true)
}
>
{moment(values.endTime).format('LT')}
</Button>
<DateTimePickerModal
cancelTextIOS={translate('general.cancel')}
confirmTextIOS={translate('general.confirm')}
date={moment(values.endTime).toDate()}
isVisible={values.displayEndTimePicker}
headerTextIOS={translate(
'abscense.selectAbscenseEndTime'
)}
// Todo fix this
locale="sv-SE"
maximumDate={maximumDate.toDate()}
minimumDate={minumumDate.toDate()}
minuteInterval={10}
mode="time"
onConfirm={(date) => {
setFieldValue('endTime', date)
setFieldValue('displayEndTimePicker', false)
}}
onCancel={() =>
setFieldValue('displayEndTimePicker', false)
}
/>
</View>
</View>
)}
<Button onPress={handleSubmit} status="primary">
{translate('general.send')}
return (
<View style={styles.wrap}>
<View style={styles.field}>
<Text style={styles.label}>
{translate('general.socialSecurityNumber')}
</Text>
<Input
testID="socialSecurityNumberInput"
keyboardType="number-pad"
onChangeText={handleChange('socialSecurityNumber')}
onBlur={handleBlur('socialSecurityNumber')}
status={hasError('socialSecurityNumber') ? 'danger' : 'basic'}
value={values.socialSecurityNumber}
style={styles.input}
accessoryRight={
hasError('socialSecurityNumber') ? AlertIcon : undefined
}
/>
{hasError('socialSecurityNumber') && (
<Text style={styles.error}>{errors.socialSecurityNumber}</Text>
)}
</View>
<View style={styles.field}>
<CheckBox
checked={values.isFullDay}
onChange={(checked) => setFieldValue('isFullDay', checked)}
>
{translate('abscense.entireDay')}
</CheckBox>
</View>
{!values.isFullDay && (
<View style={styles.partOfDay}>
<View style={styles.inputHalf}>
<Text style={styles.label}>
{translate('abscense.startTime')}
</Text>
<Button
status="basic"
style={styles.pickerButton}
onPress={() =>
setFieldValue('displayStartTimePicker', true)
}
>
{moment(values.startTime).format('LT')}
</Button>
<DateTimePickerModal
cancelTextIOS={translate('general.cancel')}
confirmTextIOS={translate('general.confirm')}
date={moment(values.startTime).toDate()}
isVisible={values.displayStartTimePicker}
headerTextIOS={translate(
'abscense.selectAbscenseStartTime'
)}
locale="sv-SE"
maximumDate={maximumDate.toDate()}
minimumDate={minumumDate.toDate()}
minuteInterval={10}
mode="time"
onConfirm={(date) => {
setFieldValue('startTime', date)
setFieldValue('displayStartTimePicker', false)
}}
onCancel={() =>
setFieldValue('displayStartTimePicker', false)
}
/>
</View>
)
}}
</Formik>
</Layout>
</SafeAreaViewContainer>
</SafeAreaView>
<View style={styles.spacer} />
<View style={styles.inputHalf}>
<Text style={styles.label}>
{translate('abscense.endTime')}
</Text>
<Button
status="basic"
style={styles.pickerButton}
onPress={() => setFieldValue('displayEndTimePicker', true)}
>
{moment(values.endTime).format('LT')}
</Button>
<DateTimePickerModal
cancelTextIOS={translate('general.cancel')}
confirmTextIOS={translate('general.confirm')}
date={moment(values.endTime).toDate()}
isVisible={values.displayEndTimePicker}
headerTextIOS={translate('abscense.selectAbscenseEndTime')}
// Todo fix this
locale="sv-SE"
maximumDate={maximumDate.toDate()}
minimumDate={minumumDate.toDate()}
minuteInterval={10}
mode="time"
onConfirm={(date) => {
setFieldValue('endTime', date)
setFieldValue('displayEndTimePicker', false)
}}
onCancel={() =>
setFieldValue('displayEndTimePicker', false)
}
/>
</View>
</View>
)}
<Button onPress={handleSubmit} status="primary">
{translate('general.send')}
</Button>
</View>
)
}}
</Formik>
)
}
export default Absence
const themedStyles = StyleService.create({
safeArea: {
...LayoutStyle.flex.full,
backgroundColor: 'background-basic-color-1',
},
topBar: {
backgroundColor: 'background-basic-color-1',
},
wrap: {
...LayoutStyle.flex.full,
padding: Sizing.t5,
padding: Sizing.t4,
backgroundColor: 'background-basic-color-2',
},
field: { marginBottom: Sizing.t4 },
partOfDay: { ...LayoutStyle.flex.row, marginBottom: Sizing.t4 },
spacer: { width: Sizing.t2 },
inputHalf: { ...LayoutStyle.flex.full },
input: {
backgroundColor: 'background-basic-color-1',
},
// TODO: Refactor to use mapping.json in eva design
pickerButton: {
backgroundColor: 'background-basic-color-1',
},
label: {
...Typography.fontSize.xs,
...Typography.fontWeight.bold,
@ -293,11 +268,4 @@ const themedStyles = StyleService.create({
error: {
color: 'color-primary-600',
},
topNavigationTitle: {
...Typography.fontWeight.semibold,
},
topNavigationSubtitle: {
...Typography.fontWeight.regular,
...Typography.fontSize.sm,
},
})

View File

@ -1,23 +1,30 @@
import { StackNavigationProp } from '@react-navigation/stack'
import {
Layout,
Text,
TopNavigation,
TopNavigationAction,
StyleService,
Text,
useStyleSheet,
useTheme,
} from '@ui-kitten/components'
import React from 'react'
import { Keyboard, TouchableWithoutFeedback, View } from 'react-native'
import { Login } from './login.component'
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
import { SafeAreaViewContainer } from '../ui/safeAreaViewContainer.component'
import { translate, languages } from '../utils/translation'
import { GlobeIcon } from './icon.component'
import { StackNavigationProp } from '@react-navigation/stack'
import { RootStackParamList } from './navigation.component'
import { SafeAreaView } from '../ui/safeAreaView.component'
import { KeyboardAvoidingView } from '../ui/keyboardAvoidingView.component'
import {
Image,
ImageStyle,
Keyboard,
TouchableWithoutFeedback,
View,
} from 'react-native'
import { TouchableOpacity } from 'react-native-gesture-handler'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import { LanguageService } from '../services/languageService'
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
import { fontSize } from '../styles/typography'
import { KeyboardAvoidingView } from '../ui/keyboardAvoidingView.component'
import { SafeAreaView } from '../ui/safeAreaView.component'
import { SafeAreaViewContainer } from '../ui/safeAreaViewContainer.component'
import { languages, translate } from '../utils/translation'
import { GlobeIcon } from './icon.component'
import { Login } from './login.component'
import { RootStackParamList } from './navigation.component'
const randomWord = () => {
const words = translate('auth.words')
@ -34,8 +41,17 @@ interface AuthProps {
navigation: StackNavigationProp<RootStackParamList, 'Login'>
}
export const authRouteOptions = (): NativeStackNavigationOptions => {
return {
headerShown: false,
replaceAnimation: 'push',
stackAnimation: 'fade',
}
}
export const Auth: React.FC<AuthProps> = ({ navigation }) => {
const styles = useStyleSheet(themeStyles)
const colors = useTheme()
const currentLanguage = LanguageService.getLanguageCode()
const currentLanguageName = languages.find(
@ -43,65 +59,104 @@ export const Auth: React.FC<AuthProps> = ({ navigation }) => {
)?.languageLocalName
return (
<KeyboardAvoidingView>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<SafeAreaView>
<SafeAreaViewContainer>
<TopNavigation
alignment="start"
subtitle={currentLanguageName}
accessoryLeft={() => (
<TopNavigationAction
accessibilityHint={translate(
'auth.a11y_navigate_to_change_language',
{
defaultValue: 'Navigerar till vyn för att byta språk',
}
)}
accessibilityLabel={translate('auth.a11y_change_language', {
defaultValue: 'Byt språk',
})}
accessible={true}
icon={GlobeIcon}
onPress={() => navigation.navigate('SetLanguage')}
/>
<SafeAreaView>
<SafeAreaViewContainer>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={LayoutStyle.flex.full}>
<TouchableOpacity
onPress={() => navigation.navigate('SetLanguage')}
accessibilityHint={translate(
'auth.a11y_navigate_to_change_language',
{
defaultValue: 'Navigerar till vyn för att byta språk',
}
)}
/>
<View style={styles.content}>
<Layout style={styles.container}>
<Text category="h2" adjustsFontSizeToFit numberOfLines={1}>
{translate('general.title')}
</Text>
<Text style={styles.subtitle}>
{translate('auth.subtitle', {
word: randomWord(),
})}
</Text>
<Login />
</Layout>
</View>
</SafeAreaViewContainer>
</SafeAreaView>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
accessibilityLabel={translate('auth.a11y_change_language', {
defaultValue: 'Byt språk',
})}
>
<View style={styles.language}>
<GlobeIcon
height={24}
width={24}
fill={colors['color-primary-500']}
/>
<Text style={styles.languageText}>{currentLanguageName}</Text>
</View>
</TouchableOpacity>
<KeyboardAvoidingView>
<View style={styles.content}>
<View style={styles.imageWrapper}>
<Image
source={require('../assets/boys.png')}
style={styles.image as ImageStyle}
accessibilityHint={translate('login.a11y_image_two_boys', {
defaultValue: 'Bild på två personer som kollar i mobilen',
})}
resizeMode="contain"
accessibilityIgnoresInvertColors={false}
/>
</View>
<View style={styles.container}>
<Text
category="h1"
style={styles.header}
adjustsFontSizeToFit
numberOfLines={2}
>
{translate('general.title')}
</Text>
<Login />
<Text category="c2" style={styles.subtitle}>
{translate('auth.subtitle', {
word: randomWord(),
})}
</Text>
</View>
</View>
</KeyboardAvoidingView>
</View>
</TouchableWithoutFeedback>
</SafeAreaViewContainer>
</SafeAreaView>
)
}
const themeStyles = StyleService.create({
container: {
...LayoutStyle.mainAxis.center,
...LayoutStyle.mainAxis.flexStart,
...LayoutStyle.crossAxis.flexEnd,
padding: Sizing.t5,
padding: Sizing.t6,
},
imageWrapper: {
flex: 1,
justifyContent: 'flex-end',
},
image: {
...Sizing.aspectRatio(1.5, Sizing.Ratio['4:3']),
},
content: {
...LayoutStyle.center,
...LayoutStyle.flex.full,
},
header: {
width: '60%',
marginBottom: Sizing.t5,
fontFamily: 'Poppins-Black',
fontWeight: '900',
},
subtitle: {
...Typography.align.center,
...Typography.fontSize.base,
...Typography.fontWeight.bold,
color: 'color-basic-500',
marginTop: Sizing.t1,
width: '100%',
textAlign: 'center',
...Typography.fontSize.xs,
marginTop: Sizing.t5,
},
language: {
flexDirection: 'row',
alignItems: 'center',
paddingLeft: Sizing.t4,
},
languageText: {
...fontSize.xs,
marginLeft: Sizing.t1,
},
})

View File

@ -65,12 +65,12 @@ export const Calendar = () => {
const themedStyles = StyleService.create({
container: {
backgroundColor: 'background-basic-color-2',
backgroundColor: 'background-basic-color-1',
height: '100%',
width: '100%',
},
description: {
...Typography.fontSize.xs,
color: 'color-basic-600',
color: 'text-hint-color',
},
})

View File

@ -1,182 +1,126 @@
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import {
BottomTabBarOptions,
BottomTabBarProps,
createBottomTabNavigator,
} from '@react-navigation/bottom-tabs'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
getFocusedRouteNameFromRoute,
RouteProp,
useRoute,
} from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import {
BottomNavigation,
BottomNavigationTab,
Layout,
StyleService,
Text,
TopNavigation,
TopNavigationAction,
useStyleSheet,
} from '@ui-kitten/components'
import { Icon } from '@ui-kitten/components'
import React from 'react'
import { StyleProp, TextProps } from 'react-native'
import { studentName } from '../utils/peopleHelpers'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import { defaultStackStyling } from '../design/navigationThemes'
import { translate } from '../utils/translation'
import { Calendar } from './calendar.component'
import { ChildProvider } from './childContext.component'
import { Menu } from './menu.component'
import {
BackIcon,
CalendarOutlineIcon,
MenuIcon,
NewsIcon,
NotificationsIcon,
} from './icon.component'
import { RootStackParamList } from './navigation.component'
import { NewsList } from './newsList.component'
import { NotificationsList } from './notificationsList.component'
import { translate } from '../utils/translation'
import { SafeAreaView } from '../ui/safeAreaView.component'
import { SafeAreaViewContainer } from '../ui/safeAreaViewContainer.component'
import { Typography } from '../styles'
type ChildNavigationProp = StackNavigationProp<RootStackParamList, 'Child'>
type ChildRouteProps = RouteProp<RootStackParamList, 'Child'>
export type ChildTabParamList = {
News: undefined
Notifications: undefined
Calendar: undefined
Menu: undefined
}
interface TabTitleProps {
children: string
style?: StyleProp<TextProps>
}
const { Navigator, Screen } = createBottomTabNavigator()
const { Navigator, Screen } = createBottomTabNavigator<ChildTabParamList>()
const NewsScreen = () => {
return (
<Layout>
<NewsList />
</Layout>
)
}
const NewsScreen = () => <NewsList />
const NotificationsScreen = () => <NotificationsList />
const CalendarScreen = () => <Calendar />
const MenuScreen = () => <Menu />
const NotificationsScreen = () => {
return (
<Layout>
<NotificationsList />
</Layout>
)
}
const CalendarScreen = () => {
return (
<Layout>
<Calendar />
</Layout>
)
}
const MenuScreen = () => {
return (
<Layout>
<Menu />
</Layout>
)
}
const TabTitle = ({ style, children }: TabTitleProps) => (
<Text
maxFontSizeMultiplier={1.5}
adjustsFontSizeToFit
numberOfLines={1}
style={style}
>
{children}
</Text>
)
const BottomTabBar = ({
navigation,
state,
}: BottomTabBarProps<BottomTabBarOptions>) => (
<BottomNavigation
accessibilityRole="menu"
selectedIndex={state.index}
onSelect={(index) => navigation.navigate(state.routeNames[index])}
>
<BottomNavigationTab
accessibilityRole="menuitem"
title={(props) => (
<TabTitle {...props}>{translate('navigation.news')}</TabTitle>
)}
icon={NewsIcon}
/>
<BottomNavigationTab
accessibilityRole="menuitem"
title={(props) => (
<TabTitle {...props}>{translate('navigation.notifications')}</TabTitle>
)}
icon={NotificationsIcon}
/>
<BottomNavigationTab
accessibilityRole="menuitem"
title={(props) => (
<TabTitle {...props}>{translate('navigation.calender')}</TabTitle>
)}
icon={CalendarOutlineIcon}
/>
<BottomNavigationTab
accessibilityRole="menuitem"
title={(props) => (
<TabTitle {...props}>{translate('navigation.menu')}</TabTitle>
)}
icon={MenuIcon}
/>
</BottomNavigation>
)
const TabNavigator = ({ initialRouteName = 'Nyheter' }) => (
const TabNavigator = ({
initialRouteName = 'News',
}: {
initialRouteName: keyof ChildTabParamList
}) => (
<Navigator
initialRouteName={initialRouteName}
tabBar={(props) => <BottomTabBar {...props} />}
screenOptions={({ route }) => {
return {
tabBarIcon: ({ focused, color }) => {
let iconName = 'news'
if (route.name === 'News')
iconName = focused ? 'book-open' : 'book-open-outline'
else if (route.name === 'Notifications')
iconName = focused ? 'alert-circle' : 'alert-circle-outline'
else if (route.name === 'Calendar')
iconName = focused ? 'calendar' : 'calendar-outline'
else if (route.name === 'Menu')
iconName = focused ? 'clipboard' : 'clipboard-outline'
return <Icon name={iconName} fill={color} height={24} width={24} />
},
}
}}
>
<Screen name={'navigation.news'} component={NewsScreen} />
<Screen name={'navigation.notifications'} component={NotificationsScreen} />
<Screen name={'navigation.calender'} component={CalendarScreen} />
<Screen name={'navigation.menu'} component={MenuScreen} />
<Screen
name="News"
component={NewsScreen}
options={{ title: translate('navigation.news') }}
/>
<Screen
name="Notifications"
component={NotificationsScreen}
options={{ title: translate('navigation.notifications') }}
/>
<Screen
name="Calendar"
component={CalendarScreen}
options={{ title: translate('navigation.calender') }}
/>
<Screen
name="Menu"
component={MenuScreen}
options={{ title: translate('navigation.menu') }}
/>
</Navigator>
)
export const Child = () => {
const navigation = useNavigation<ChildNavigationProp>()
const route = useRoute<ChildRouteProps>()
const { child, initialRouteName } = route.params
const styles = useStyleSheet(themedStyles)
const getHeaderTitle = (route: any) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'News'
const BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={navigateBack} />
)
const navigateBack = () => {
navigation.goBack()
switch (routeName) {
case 'News':
return translate('navigation.news')
case 'Notifications':
return translate('navigation.notifications')
case 'Calendar':
return translate('navigation.calender')
case 'Menu':
return translate('navigation.menu')
}
return (
<SafeAreaView>
<SafeAreaViewContainer>
<ChildProvider child={child}>
<TopNavigation
title={() => (
<Text maxFontSizeMultiplier={2} style={styles.topNavigationTitle}>
{studentName(child.name)}
</Text>
)}
alignment="center"
accessoryLeft={BackAction}
/>
<TabNavigator initialRouteName={initialRouteName} />
</ChildProvider>
</SafeAreaViewContainer>
</SafeAreaView>
)
}
const themedStyles = StyleService.create({
topNavigationTitle: {
...Typography.fontWeight.semibold,
},
})
export const childRouteOptions = ({
route,
}: {
route: RouteProp<RootStackParamList, 'Child'>
}): NativeStackNavigationOptions => {
return {
...defaultStackStyling,
title: getHeaderTitle(route),
}
}
export const Child = () => {
const route = useRoute<ChildRouteProps>()
const { child, initialRouteName } = route.params
return (
<ChildProvider child={child}>
<TabNavigator initialRouteName={initialRouteName as any} />
</ChildProvider>
)
}

View File

@ -3,34 +3,26 @@ import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import {
useCalendar,
useMenu,
useNews,
useNotifications,
useSchedule,
} from '@skolplattformen/api-hooks'
import { Child } from '@skolplattformen/embedded-api'
import {
Avatar,
Button,
Card,
StyleService,
Text,
useStyleSheet,
} from '@ui-kitten/components'
import moment from 'moment'
import React from 'react'
import { View } from 'react-native'
import { TouchableOpacity, View } from 'react-native'
import { Layout, Sizing } from '../styles'
import { studentName } from '../utils/peopleHelpers'
import { translate } from '../utils/translation'
import {
CalendarOutlineIcon,
MenuIcon,
NewsIcon,
NotificationsIcon,
} from './icon.component'
import { RootStackParamList } from './navigation.component'
import { StudentAvatar } from './studentAvatar.component'
import { DaySummary } from './daySummary.component'
interface ChildListItemProps {
child: Child
@ -40,22 +32,20 @@ type ChildListItemNavigationProp = StackNavigationProp<
RootStackParamList,
'Children'
>
export const ChildListItem = ({ child, color }: ChildListItemProps) => {
// Forces rerender when child.id changes
React.useEffect(() => {}, [child.id])
const navigation = useNavigation<ChildListItemNavigationProp>()
const { data: notifications, status: notificationsStatus } = useNotifications(
child
)
const { data: news, status: newsStatus } = useNews(child)
const { data: calendar, status: calendarStatus } = useCalendar(child)
const { data: notifications } = useNotifications(child)
const { data: news } = useNews(child)
const { data: calendar } = useCalendar(child)
const { data: schedule } = useSchedule(
child,
moment().toISOString(),
moment().add(7, 'days').toISOString()
)
const { status: menuStatus } = useMenu(child)
const notificationsThisWeek = notifications.filter(({ dateCreated }) =>
dateCreated ? moment(dateCreated).isSame(moment(), 'week') : false
@ -105,189 +95,103 @@ export const ChildListItem = ({ child, color }: ChildListItemProps) => {
const className = getClassName()
const styles = useStyleSheet(themeStyles)
const statusColors = {
loading: 'basic',
loaded: 'basic',
error: 'error',
pending: 'basic',
}
const buttonAppearance: string = 'ghost'
const Footer = () => {
return (
<View style={styles.itemFooter}>
<Button
style={styles.item}
accessible={true}
accessibilityLabel={`${child.name}, ${translate('navigation.news')}`}
accessibilityRole="button"
size="small"
appearance={buttonAppearance}
status={statusColors[newsStatus]}
onPress={() =>
navigation.navigate('Child', {
child,
color,
initialRouteName: 'navigation.news',
})
}
accessoryLeft={NewsIcon}
>
{`${(news || []).length}`}
</Button>
<Button
style={styles.item}
accessible={true}
accessibilityLabel={`${child.name}, ${translate(
'navigation.notifications'
)}`}
accessibilityRole="button"
size="small"
appearance={buttonAppearance}
status={statusColors[notificationsStatus]}
onPress={() =>
navigation.navigate('Child', {
child,
color,
initialRouteName: 'navigation.notifications',
})
}
accessoryLeft={NotificationsIcon}
>
{`${(notifications || []).length}`}
</Button>
<Button
style={styles.item}
accessible={true}
accessibilityLabel={`${child.name}, ${translate(
'navigation.calender'
)}`}
accessibilityRole="button"
size="small"
appearance={buttonAppearance}
status={statusColors[calendarStatus]}
onPress={() =>
navigation.navigate('Child', {
child,
color,
initialRouteName: 'navigation.calender',
})
}
accessoryLeft={CalendarOutlineIcon}
>
{`${(calendar || []).length}`}
</Button>
<Button
style={styles.item}
accessible={true}
accessibilityLabel={`${child.name}, ${translate('navigation.menu')}`}
accessibilityRole="button"
size="small"
appearance={buttonAppearance}
status={statusColors[menuStatus]}
onPress={() =>
navigation.navigate('Child', {
child,
color,
initialRouteName: 'navigation.menu',
})
}
accessoryLeft={MenuIcon}
/>
</View>
)
}
const date = moment()
return (
<Card
style={styles.card}
appearance="filled"
status={color}
header={(props) => (
<View {...props} style={styles.cardHeader}>
<View style={styles.cardAvatar}>
<Avatar source={require('../assets/avatar.png')} shape="square" />
</View>
<View style={styles.cardHeaderText}>
<Text category="h6">{studentName(child.name)}</Text>
{className ? <Text category="s1">{className}</Text> : null}
</View>
</View>
)}
footer={Footer}
<TouchableOpacity
onPress={() => navigation.navigate('Child', { child, color })}
>
{scheduleAndCalendarThisWeek.slice(0, 3).map((calendarItem, i) => (
<Text category="p1" key={i}>
{`${calendarItem.title} (${displayDate(calendarItem.startDate)})`}
</Text>
))}
{notificationsThisWeek.slice(0, 3).map((notification, i) => (
<Text category="p1" key={i}>
{translate('notifications.notificationTitle', {
message: notification.message,
dateCreated: displayDate(notification.dateCreated),
})}
</Text>
))}
{newsThisWeek.slice(0, 3).map((newsItem, i) => (
<Text category="p1" key={i}>
{translate('news.notificationTitle', {
header: newsItem.header,
published: displayDate(newsItem.published),
})}
</Text>
))}
{scheduleAndCalendarThisWeek.length ||
notificationsThisWeek.length ||
newsThisWeek.length ? null : (
<Text category="p1" style={styles.noNewNewsItemsText}>
{translate('news.noNewNewsItemsThisWeek')}
</Text>
)}
<View style={styles.itemFooterAbsence}>
<Button
accessible={true}
accessibilityRole="button"
accessibilityLabel={`${child.name}, ${translate('abscense.title')}`}
size="small"
status="primary"
onPress={() => navigation.navigate('Absence', { child })}
>
{translate('abscense.title')}
</Button>
<View style={styles.card}>
<View style={styles.cardHeader}>
<View style={styles.cardHeaderLeft}>
<StudentAvatar name={studentName(child.name)} color={color} />
<View style={styles.cardHeaderText}>
<Text category="h6">{studentName(child.name)}</Text>
{className ? <Text category="s1">{className}</Text> : null}
</View>
</View>
</View>
{/*<DaySummary child={child} date={date} />*/}
{scheduleAndCalendarThisWeek.slice(0, 3).map((calendarItem, i) => (
<Text category="p1" key={i}>
{`${calendarItem.title} (${displayDate(calendarItem.startDate)})`}
</Text>
))}
{notificationsThisWeek.slice(0, 3).map((notification, i) => (
<Text category="p1" key={i}>
{translate('notifications.notificationTitle', {
message: notification.message,
dateCreated: displayDate(notification.dateCreated),
})}
</Text>
))}
{newsThisWeek.slice(0, 3).map((newsItem, i) => (
<Text category="p1" key={i}>
{translate('news.notificationTitle', {
header: newsItem.header,
published: displayDate(newsItem.published),
})}
</Text>
))}
{scheduleAndCalendarThisWeek.length ||
notificationsThisWeek.length ||
newsThisWeek.length ? null : (
<Text category="p1" style={styles.noNewNewsItemsText}>
{translate('news.noNewNewsItemsThisWeek')}
</Text>
)}
<View style={styles.itemFooterAbsence}>
<Button
accessible
accessibilityRole="button"
accessibilityLabel={`${child.name}, ${translate('abscense.title')}`}
size="small"
status="basic"
onPress={() => navigation.navigate('Absence', { child })}
>
{translate('abscense.title')}
</Button>
</View>
</View>
</Card>
</TouchableOpacity>
)
}
const themeStyles = StyleService.create({
card: {
marginBottom: Sizing.t5,
borderRadius: 25,
padding: Sizing.t5,
marginBottom: Sizing.t4,
backgroundColor: 'background-basic-color-1',
},
cardHeader: {
...Layout.flex.row,
...Layout.mainAxis.center,
...Layout.crossAxis.spaceBetween,
marginBottom: Sizing.t4,
},
cardHeaderLeft: {
...Layout.flex.row,
...Layout.mainAxis.center,
flex: 1,
},
cardHeaderText: {
marginHorizontal: Sizing.t4,
flex: 1,
},
cardAvatar: { margin: Sizing.t5, marginRight: 0 },
cardHeaderText: { margin: Sizing.t5, flex: 1 },
itemFooter: {
...Layout.flex.row,
...Layout.crossAxis.evenly,
paddingVertical: Sizing.t2,
borderRadius: 5,
margin: 0,
marginTop: Sizing.t4,
},
itemFooterAbsence: {
...Layout.mainAxis.flexStart,
marginTop: Sizing.t4,
},
item: {
paddingHorizontal: 0,
},
noNewNewsItemsText: {
color: 'color-basic-600',
marginRight: 12,
paddingHorizontal: 2,
paddingVertical: 0,
marginBottom: 0,
},
noNewNewsItemsText: {},
})

View File

@ -1,54 +1,71 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import { useNavigation } from '@react-navigation/core'
import { useApi, useChildList } from '@skolplattformen/api-hooks'
import { Child } from '@skolplattformen/embedded-api'
import {
Button,
Divider,
Layout,
List,
Spinner,
StyleService,
Text,
TopNavigation,
TopNavigationAction,
useTheme,
useStyleSheet,
} from '@ui-kitten/components'
import React from 'react'
import React, { useCallback, useEffect, useMemo } from 'react'
import {
Image,
ListRenderItemInfo,
StyleSheet,
View,
ImageStyle,
Linking,
ListRenderItemInfo,
View,
} from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import ActionSheet from 'rn-actionsheet-module'
import { defaultStackStyling } from '../design/navigationThemes'
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 { CloseOutlineIcon } from './icon.component'
const colors = ['primary', 'success', 'info', 'warning', 'danger']
export const childenRouteOptions = (): NativeStackNavigationOptions => {
return {
...defaultStackStyling,
title: translate('children.title'),
headerLargeTitle: true,
headerLargeTitleHideShadow: true,
}
}
export const Children = () => {
const settingsOptions = [
translate('general.logout'),
translate('general.cancel'),
]
const theme = useTheme()
const styles = useStyleSheet(themedStyles)
const navigation = useNavigation()
const { api } = useApi()
const { data: childList, status, reload } = useChildList()
const insets = useSafeAreaInsets()
const handleSettingSelection = (index: number) => {
switch (index) {
case 0:
logout()
break
}
let { data: childList, status, reload } = useChildList()
const reloadChildren = () => {
reload()
}
const settings = () => {
const logout = useCallback(() => {
api.logout()
AsyncStorage.clear()
}, [api])
const settingsOptions = useMemo(() => {
return [translate('general.logout'), translate('general.cancel')]
}, [])
const handleSettingSelection = useCallback(
(index: number) => {
if (index === 0) logout()
},
[logout]
)
const settings = useCallback(() => {
const options = {
cancelButtonIndex: 1,
title: translate('general.settings'),
@ -58,126 +75,93 @@ export const Children = () => {
}
ActionSheet(options, handleSettingSelection)
}
}, [handleSettingSelection, settingsOptions])
const reloadChildren = () => {
reload()
}
const logout = () => {
api.logout()
AsyncStorage.clear()
}
useEffect(() => {
navigation.setOptions({
headerLeft: () => {
return <TopNavigationAction icon={CloseOutlineIcon} onPress={settings} />
},
})
}, [navigation, settings])
// 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 (
<View
style={[
{
...styles.topContainer,
paddingTop: insets.top,
},
{ backgroundColor: theme['background-basic-color-1'] },
]}
>
<>
{status === 'loaded' ? (
<>
<TopNavigation
title={() => (
<Text
maxFontSizeMultiplier={2.5}
style={styles.topNavigationTitle}
<>
{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}>
<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.title')}
</Text>
)}
alignment="center"
accessoryRight={() => (
<TopNavigationAction icon={SettingsIcon} onPress={settings} />
)}
/>
<Divider />
<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}
/>
</View>
}
renderItem={({
item: child,
index,
}: ListRenderItemInfo<Child>) => (
<ChildListItem
child={child}
color={colors[index % colors.length]}
key={child.id}
/>
)}
/>
</>
) : (
<Layout style={styles.loading}>
<Image
accessibilityIgnoresInvertColors={false}
source={require('../assets/girls.png')}
style={styles.loadingImage}
/>
{status === 'error' ? (
<View style={styles.errorMessage}>
<Text category="h5">
{translate('children.loadingErrorHeading')}
</Text>
<Text style={{ fontSize: Sizing.t5 }}>
{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>
{translate('children.viewStatus')}
</Button>
<Button onPress={() => logout()}>
{translate('general.logout')}
</Button>
</View>
) : (
<View style={styles.loadingMessage}>
<Spinner size="large" status="warning" />
<Text category="h1" style={styles.loadingText}>
{translate('general.loading')}
</Text>
</View>
)}
</Layout>
)}
</>
</View>
</View>
) : (
<View style={styles.loadingMessage}>
<Spinner size="large" status="primary" />
<Text category="h1" style={styles.loadingText}>
{translate('general.loading')}
</Text>
</View>
)}
</View>
)}
</>
)
}
const styles = StyleSheet.create({
const themedStyles = StyleService.create({
topContainer: {
...LayoutStyle.flex.full,
paddingBottom: 0,
@ -216,7 +200,8 @@ const styles = StyleSheet.create({
...LayoutStyle.flex.full,
},
childListContainer: {
padding: Sizing.t5,
paddingVertical: Sizing.t4,
paddingHorizontal: Sizing.t3,
},
emptyState: {
...LayoutStyle.center,

View File

@ -0,0 +1,53 @@
import React from 'react'
import { useTimetable } from '@skolplattformen/api-hooks'
import { Child } from '@skolplattformen/embedded-api'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import moment, { Moment } from 'moment'
import { View } from 'react-native'
import { LanguageService } from '../services/languageService'
import { translate } from '../utils/translation'
interface DaySummaryProps {
child: Child
date: Moment
}
export const DaySummary = ({ child, date }: DaySummaryProps) => {
const styles = useStyleSheet(themedStyles)
const [year, week] = [moment().isoWeekYear(), moment().isoWeek()]
const { data: weekLessons } = useTimetable(
child,
week,
year,
LanguageService.getLanguageCode()
)
const lessons = weekLessons
.filter((lesson) => lesson.dayOfWeek === date.isoWeekday())
.sort((a, b) => a.dateStart.localeCompare(b.dateStart))
const gymBag = lessons.some((lesson) => lesson.code === 'IDH')
if (lessons.length <= 0) {
return null
}
return (
<View style={styles.summary}>
<Text category="h5">
{lessons[0].timeStart.slice(0, 5)}-
{lessons[lessons.length - 1].timeEnd.slice(0, 5)}
{gymBag
? ` (🤼‍♀️ ${translate('schedule.gymBag', {
defaultValue: 'Gympapåse',
})})`
: ''}
</Text>
</View>
)
}
const themedStyles = StyleService.create({
summary: {
flexDirection: 'row',
},
})

View File

@ -1,7 +1,9 @@
import { Icon } from '@ui-kitten/components'
import { Icon, IconProps } from '@ui-kitten/components'
import React from 'react'
const uiIcon = (name: string) => (props: any) => <Icon {...props} name={name} />
const uiIcon = (name: string) => (props: IconProps) => (
<Icon {...props} name={name} />
)
export const AlertIcon = uiIcon('alert-circle-outline')
export const BackIcon = uiIcon('arrow-back')
@ -26,3 +28,4 @@ export const SearchIcon = uiIcon('search-outline')
export const BookOpenIcon = uiIcon('book-open-outline')
export const GlobeIcon = uiIcon('globe-outline')
export const ExternalLinkIcon = uiIcon('external-link-outline')
export const ClipboardIcon = uiIcon('clipboard-outline')

View File

@ -1,16 +1,22 @@
import { StyleService, useStyleSheet } from '@ui-kitten/components'
import React from 'react'
import { ActivityIndicator, View, StyleSheet } from 'react-native'
import { ActivityIndicator, View } from 'react-native'
export const LoadingComponent = () => (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator size="large" />
</View>
)
export const LoadingComponent = () => {
const styles = useStyleSheet(themedStyles)
const styles = StyleSheet.create({
return (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator size="large" />
</View>
)
}
const themedStyles = StyleService.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'background-basic-color-2',
},
horizontal: {
flexDirection: 'row',

View File

@ -23,16 +23,23 @@ import {
} from 'react-native'
import { useAsyncStorage } from 'use-async-storage'
import { schema } from '../app.json'
import { Layout, Sizing } from '../styles'
import { Layout } from '../styles'
import { translate } from '../utils/translation'
import {
CheckIcon,
CloseOutlineIcon,
PersonIcon,
SecureIcon,
SelectIcon,
} from './icon.component'
const BankId = () => (
<Image
style={themedStyles.icon}
source={require('../assets/bankid_low_rgb.png')}
accessibilityIgnoresInvertColors
/>
)
export const Login = () => {
const { api } = useApi()
const [cancelLoginRequest, setCancelLoginRequest] = useState<
@ -54,7 +61,9 @@ export const Login = () => {
translate('auth.bankid.OpenOnThisDevice'),
translate('auth.bankid.OpenOnAnotherDevice'),
translate('auth.loginAsTestUser'),
translate('general.cancel'),
]
useEffect(() => {
if (loginMethodIndex !== parseInt(cachedLoginMethodIndex, 10)) {
setCachedLoginMethodIndex(loginMethodIndex.toString())
@ -144,15 +153,6 @@ export const Login = () => {
return (
<>
<Image
source={require('../assets/boys.png')}
// @ts-expect-error Don't know why this occurs
style={styles.image}
accessibilityHint={translate('login.a11y_image_two_boys', {
defaultValue: 'Bild på två personer som kollar i mobilen',
})}
accessibilityIgnoresInvertColors={false}
/>
<View style={styles.loginForm}>
{loginMethodIndex === 1 && (
<Input
@ -183,7 +183,7 @@ export const Login = () => {
placeholder={translate('auth.placeholder_SocialSecurityNumber')}
/>
)}
<ButtonGroup style={styles.loginButtonGroup}>
<ButtonGroup style={styles.loginButtonGroup} status="primary">
<Button
accessible={true}
onPress={() => startLogin(socialSecurityNumber)}
@ -191,7 +191,7 @@ export const Login = () => {
appearance="ghost"
disabled={loginMethodIndex === 1 && !valid}
status="primary"
accessoryLeft={SecureIcon}
accessoryLeft={BankId}
size="medium"
>
{loginMethods[loginMethodIndex]}
@ -278,17 +278,11 @@ export const Login = () => {
}
const themedStyles = StyleService.create({
image: {
...Sizing.aspectRatio(0.9, Sizing.Ratio['4:3']),
marginVertical: Sizing.t4,
},
backdrop: {
backgroundColor: 'color-basic-transparent-600',
},
loginForm: {
...Layout.mainAxis.flexStart,
...Layout.crossAxis.flexEnd,
paddingHorizontal: Sizing.t4,
},
pnrInput: { minHeight: 70 },
loginButtonGroup: {
@ -301,4 +295,8 @@ const themedStyles = StyleService.create({
},
bankIdLoading: { margin: 10 },
cancelButtonStyle: { marginTop: 15 },
icon: {
width: 20,
height: 20,
},
})

View File

@ -1,15 +1,22 @@
import { useMenu } from '@skolplattformen/api-hooks'
import { MenuItem } from '@skolplattformen/embedded-api'
import { List, Text } from '@ui-kitten/components'
import {
Divider,
List,
StyleService,
Text,
useStyleSheet,
} from '@ui-kitten/components'
import 'moment/locale/sv'
import React from 'react'
import { Image, ListRenderItemInfo, StyleSheet, View } from 'react-native'
import { Sizing, Layout as LayoutStyle, Typography } from '../styles'
import { Image, ImageStyle, ListRenderItemInfo, View } from 'react-native'
import { Layout as LayoutStyle, Sizing, Typography } from '../styles'
import { translate } from '../utils/translation'
import { useChild } from './childContext.component'
import { MenuListItem } from './menuListItem.component'
export const Menu = () => {
const styles = useStyleSheet(themedStyles)
const child = useChild()
const { data } = useMenu(child)
@ -17,6 +24,7 @@ export const Menu = () => {
<List
contentContainerStyle={styles.contentContainer}
data={data}
ItemSeparatorComponent={Divider}
ListEmptyComponent={
<View style={styles.emptyState}>
<Text category="h4">{translate('menu.emptyHeadline')}</Text>
@ -26,7 +34,7 @@ export const Menu = () => {
<Image
accessibilityIgnoresInvertColors={false}
source={require('../assets/children.png')}
style={styles.emptyStateImage}
style={styles.emptyStateImage as ImageStyle}
/>
</View>
}
@ -38,23 +46,26 @@ export const Menu = () => {
)
}
const styles = StyleSheet.create({
const themedStyles = StyleService.create({
container: {
height: '100%',
width: '100%',
padding: Sizing.t3,
},
contentContainer: {
padding: Sizing.t3,
paddingHorizontal: Sizing.t5,
paddingVertical: Sizing.t2,
backgroundColor: 'background-basic-color-1',
borderRadius: 25,
},
emptyState: {
...LayoutStyle.center,
...LayoutStyle.flex.full,
paddingHorizontal: Sizing.t5,
paddingTop: 25,
},
emptyStateDescription: {
...Typography.align.center,
lineHeight: 21,
paddingHorizontal: Sizing.t3,
marginTop: Sizing.t3,
},
emptyStateImage: {

View File

@ -1,7 +1,7 @@
import { Text, Card, StyleService, useStyleSheet } from '@ui-kitten/components'
import { MenuItem } from '@skolplattformen/embedded-api'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import React from 'react'
import { View } from 'react-native'
import { MenuItem } from '@skolplattformen/embedded-api'
import { Sizing, Typography } from '../styles'
interface MenuListItemProps {
@ -12,16 +12,8 @@ export const MenuListItem = ({ item }: MenuListItemProps) => {
const styles = useStyleSheet(themedStyles)
return (
<View style={styles.container}>
<Card
header={(props) => (
<View {...props}>
<Text style={styles.title}>{item.title}</Text>
</View>
)}
style={styles.contentContainer}
>
<Text category="p1">{item.description}</Text>
</Card>
<Text style={styles.title}>{item.title}</Text>
<Text category="p1">{item.description}</Text>
</View>
)
}
@ -29,10 +21,7 @@ export const MenuListItem = ({ item }: MenuListItemProps) => {
const themedStyles = StyleService.create({
container: {
width: '100%',
},
contentContainer: {
marginBottom: Sizing.t2,
justifyContent: 'flex-start',
paddingVertical: Sizing.t3,
},
topContainer: {
margin: Sizing.t1,
@ -41,6 +30,6 @@ const themedStyles = StyleService.create({
},
title: {
...Typography.header,
color: 'color-basic-800',
marginBottom: Sizing.t1,
},
})

View File

@ -88,7 +88,7 @@ export const ModalWebView = ({
const themedStyles = StyleService.create({
container: {
flex: 1,
backgroundColor: 'background-basic-color-1',
backgroundColor: 'background-basic-color-2',
},
headerWrapper: {
marginTop: Sizing.t1,
@ -96,7 +96,7 @@ const themedStyles = StyleService.create({
borderRadius: 2,
borderColor: 'basic-color-200',
borderBottomWidth: 1,
backgroundColor: 'background-basic-color-1',
backgroundColor: 'background-basic-color-2',
},
backdrop: {
backgroundColor: 'color-basic-transparent-600',
@ -111,7 +111,7 @@ const themedStyles = StyleService.create({
...Layout.mainAxis.center,
paddingHorizontal: Sizing.t3,
paddingVertical: Sizing.t1,
backgroundColor: 'background-basic-color-1',
backgroundColor: 'background-basic-color-2',
},
shareIcon: {
width: 24,

View File

@ -1,20 +1,25 @@
import { useApi } from '@skolplattformen/api-hooks'
import { NavigationContainer } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
import React, { useEffect } from 'react'
import { StatusBar } from 'react-native'
import { schema } from '../app.json'
import Absence from './absence.component'
import { Child } from './child.component'
import { Children } from './children.component'
import { Auth } from './auth.component'
import { SetLanguage } from './setLanguage.component'
import { NewsItem } from './newsItem.component'
import { useApi } from '@skolplattformen/api-hooks'
import {
Child as ChildType,
NewsItem as NewsItemType,
} from '@skolplattformen/embedded-api'
import { useTheme } from '@ui-kitten/components'
import React, { useEffect } from 'react'
import { StatusBar, useColorScheme } from 'react-native'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import { schema } from '../app.json'
import {
darkNavigationTheme,
lightNavigationTheme,
} from '../design/navigationThemes'
import { useAppState } from '../hooks/useAppState'
import Absence, { absenceRouteOptions } from './absence.component'
import { Auth, authRouteOptions } from './auth.component'
import { Child, childRouteOptions } from './child.component'
import { childenRouteOptions, Children } from './children.component'
import { NewsItem, newsItemRouteOptions } from './newsItem.component'
import { SetLanguage, setLanguageRouteOptions } from './setLanguage.component'
export type RootStackParamList = {
Login: undefined
@ -29,7 +34,7 @@ export type RootStackParamList = {
SetLanguage: undefined
}
const { Navigator, Screen } = createStackNavigator()
const { Navigator, Screen } = createNativeStackNavigator<RootStackParamList>()
const linking = {
prefixes: [schema],
@ -43,6 +48,9 @@ const linking = {
export const AppNavigator = () => {
const { isLoggedIn, api } = useApi()
const colorScheme = useColorScheme()
const colors = useTheme()
const currentAppState = useAppState()
useEffect(() => {
@ -59,20 +67,56 @@ export const AppNavigator = () => {
}, [currentAppState, isLoggedIn, api])
return (
<NavigationContainer linking={linking}>
<NavigationContainer
linking={linking}
theme={
colorScheme === 'dark' ? darkNavigationTheme : lightNavigationTheme
}
>
<StatusBar />
<Navigator headerMode="none">
<Navigator
screenOptions={() => ({
headerLargeTitle: true,
headerLargeTitleHideShadow: true,
headerStyle: {
backgroundColor: colors['background-basic-color-2'],
},
headerLargeTitleStyle: {
fontFamily: 'Poppins-ExtraBold',
},
})}
>
{isLoggedIn ? (
<>
<Screen name="Children" component={Children} />
<Screen name="Child" component={Child} />
<Screen name="NewsItem" component={NewsItem} />
<Screen name="Absence" component={Absence} />
<Screen
name="Children"
component={Children}
options={childenRouteOptions}
/>
<Screen
name="Child"
component={Child}
options={childRouteOptions}
/>
<Screen
name="NewsItem"
component={NewsItem}
options={newsItemRouteOptions}
/>
<Screen
name="Absence"
component={Absence}
options={absenceRouteOptions}
/>
</>
) : (
<>
<Screen name="Login" component={Auth} />
<Screen name="SetLanguage" component={SetLanguage} />
<Screen name="Login" component={Auth} options={authRouteOptions} />
<Screen
name="SetLanguage"
component={SetLanguage}
options={setLanguageRouteOptions}
/>
</>
)}
</Navigator>

View File

@ -0,0 +1,32 @@
import { Text } from '@ui-kitten/components'
import React from 'react'
import { StyleSheet, View } from 'react-native'
import { Layout } from '../styles'
import { fontSize } from '../styles/typography'
interface NavigationTitleProps {
title?: string
subtitle?: string
}
/**
* Navigation Title with a smaller subtitle.
*/
export const NavigationTitle = ({ title, subtitle }: NavigationTitleProps) => {
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>{subtitle}</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
...Layout.center,
},
title: {
...fontSize.base,
fontWeight: '500',
},
subtitle: { ...fontSize.xs },
})

View File

@ -1,26 +1,18 @@
import { RouteProp } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { useNewsDetails } from '@skolplattformen/api-hooks'
import {
Divider,
Text,
TopNavigation,
TopNavigationAction,
StyleService,
useStyleSheet,
} from '@ui-kitten/components'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment'
import 'moment/locale/sv'
import React from 'react'
import { ScrollView, View } from 'react-native'
import { Colors, Layout, Sizing, Typography } from '../styles'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import { defaultStackStyling } from '../design/navigationThemes'
import { Layout, Sizing, Typography } from '../styles'
import { translate } from '../utils/translation'
import { BackIcon } from './icon.component'
import { Image } from './image.component'
import { Markdown } from './markdown.component'
import { RootStackParamList } from './navigation.component'
import { SafeAreaViewContainer } from '../ui/safeAreaViewContainer.component'
import { SafeAreaView } from '../ui/safeAreaView.component'
interface NewsItemProps {
navigation: StackNavigationProp<RootStackParamList, 'NewsItem'>
@ -32,111 +24,90 @@ const displayDate = (date: string | undefined) => moment(date).format('lll')
const dateIsValid = (date: string | undefined) =>
moment(date, moment.ISO_8601).isValid()
export const NewsItem = ({ navigation, route }: NewsItemProps) => {
export const newsItemRouteOptions = ({
route,
}: {
route: RouteProp<RootStackParamList, 'NewsItem'>
}): NativeStackNavigationOptions => {
const newsItem = route.params.newsItem
return {
...defaultStackStyling,
title: newsItem.header,
headerLargeTitle: true,
headerStyle: {
// TODO: This color must come from theme for dark mode
backgroundColor: '#fff',
},
}
}
export const NewsItem = ({ route }: NewsItemProps) => {
const { newsItem, child } = route.params
const { data } = useNewsDetails(child, newsItem)
const styles = useStyleSheet(themedStyles)
const stylesMarkdown = useStyleSheet(themedStylesMarkdown)
const navigateBack = () => {
navigation.goBack()
}
const BackAction = () => (
<TopNavigationAction
testID="topNavBackToChild"
accessibilityHint={translate('news.backToChild')}
icon={BackIcon}
onPress={navigateBack}
/>
)
return (
<SafeAreaView>
<SafeAreaViewContainer>
<TopNavigation
title={() => (
<Text maxFontSizeMultiplier={1.5} style={styles.topNavigationTitle}>
{translate('news.title')}
</Text>
)}
alignment="center"
accessoryLeft={BackAction}
/>
<Divider />
<ScrollView
contentContainerStyle={styles.article}
style={styles.scrollView}
<ScrollView
contentContainerStyle={styles.article}
style={styles.scrollView}
>
{dateIsValid(newsItem.published) && (
<Text
maxFontSizeMultiplier={2}
style={[styles.subtitle, styles.published]}
>
<Text maxFontSizeMultiplier={2} style={styles.title}>
{newsItem.header}
</Text>
{dateIsValid(newsItem.published) && (
<Text
maxFontSizeMultiplier={2}
style={[styles.subtitle, styles.published]}
>
<Text style={styles.strong}>{translate('news.published')}:</Text>{' '}
{displayDate(newsItem.published)}
</Text>
)}
{dateIsValid(newsItem.modified) && (
<Text maxFontSizeMultiplier={2} style={styles.subtitle}>
<Text style={styles.strong}>{translate('news.updated')}:</Text>{' '}
{displayDate(newsItem.modified)}
</Text>
)}
<View style={styles.body}>
<Markdown style={stylesMarkdown}>{data.body}</Markdown>
{newsItem.fullImageUrl && (
<Image
accessibilityIgnoresInvertColors={false}
src={newsItem.fullImageUrl}
// @ts-expect-error Fix later on
style={styles.image}
/>
)}
</View>
</ScrollView>
</SafeAreaViewContainer>
</SafeAreaView>
<Text style={styles.strong}>{translate('news.published')}:</Text>{' '}
{displayDate(newsItem.published)}
</Text>
)}
{dateIsValid(newsItem.modified) && (
<Text maxFontSizeMultiplier={2} style={styles.subtitle}>
<Text style={styles.strong}>{translate('news.updated')}:</Text>{' '}
{displayDate(newsItem.modified)}
</Text>
)}
<View style={styles.body}>
<Markdown style={stylesMarkdown}>{data.body}</Markdown>
{newsItem.fullImageUrl && (
<Image
accessibilityIgnoresInvertColors={false}
src={newsItem.fullImageUrl}
// @ts-expect-error Fix later on
style={styles.image}
/>
)}
</View>
</ScrollView>
)
}
const themedStylesMarkdown = StyleService.create({
body: {
...Typography.fontSize.base,
color: 'color-basic-800',
color: 'text-basic-color',
lineHeight: 26,
},
heading1: {
...Typography.fontSize.xl,
color: 'color-basic-600',
color: 'text-basic-color',
},
heading2: {
...Typography.fontSize.lg,
color: 'color-basic-800',
color: 'text-basic-color',
},
code_block: {
color: 'color-basic-800',
color: 'text-basic-color',
backgroundColor: 'background-basic-color-1',
borderColor: 'color-basic-400',
},
})
const themedStyles = StyleService.create({
safeArea: {
...Layout.flex.full,
backgroundColor: Colors.neutral.white,
},
topContainer: {
...Layout.flex.row,
...Layout.crossAxis.spaceBetween,
},
article: {
padding: Sizing.t5,
backgroundColor: 'background-basic-color-2',
backgroundColor: 'background-basic-color-1',
},
scrollView: {
...Layout.flex.full,
@ -145,6 +116,7 @@ const themedStyles = StyleService.create({
width: '100%',
minHeight: 300,
marginTop: Sizing.t4,
borderRadius: 15,
},
title: {
...Typography.fontWeight.bold,
@ -153,12 +125,12 @@ const themedStyles = StyleService.create({
},
subtitle: {
...Typography.fontSize.xs,
color: 'color-basic-600',
color: 'text-hint-color',
},
strong: {
...Typography.fontSize.xs,
...Typography.fontWeight.bold,
color: 'color-basic-600',
color: 'text-hint-color',
},
published: {
marginBottom: Sizing.t1,

View File

@ -1,18 +1,19 @@
import React, { useState, useMemo } from 'react'
import { useNews } from '@skolplattformen/api-hooks'
import { List, Input } from '@ui-kitten/components'
import { StyleSheet, TouchableWithoutFeedback } from 'react-native'
import { Input, List, StyleService, useStyleSheet } from '@ui-kitten/components'
import React, { useMemo, useState } from 'react'
import { TouchableOpacity, View } from 'react-native'
import { Sizing } from '../styles'
import { useChild } from './childContext.component'
import { NewsListItem } from './newsListItem.component'
import { translate } from '../utils/translation'
import {
useNewsListSearchResults,
renderSearchResultPreview,
useNewsListSearchResults,
} from '../utils/search'
import { SearchIcon, CloseOutlineIcon } from './icon.component'
import { translate } from '../utils/translation'
import { useChild } from './childContext.component'
import { CloseOutlineIcon, SearchIcon } from './icon.component'
import { NewsListItem } from './newsListItem.component'
export const NewsList = () => {
const styles = useStyleSheet(themedStyles)
const child = useChild()
const { data } = useNews(child)
@ -33,14 +34,19 @@ export const NewsList = () => {
accessoryLeft={SearchIcon}
onChangeText={setSearchQuery}
value={searchQuery}
accessoryRight={(props) => (
<TouchableWithoutFeedback onPress={() => setSearchQuery('')}>
<CloseOutlineIcon {...props} />
</TouchableWithoutFeedback>
)}
style={styles.search}
accessoryRight={(props) =>
searchQuery.length > 0 ? (
<TouchableOpacity onPress={() => setSearchQuery('')}>
<CloseOutlineIcon {...props} />
</TouchableOpacity>
) : (
<View />
)
}
/>
),
[searchQuery]
[searchQuery, styles.search]
)
if (searchQuery) {
@ -72,12 +78,18 @@ export const NewsList = () => {
)
}
const styles = StyleSheet.create({
const themedStyles = StyleService.create({
container: {
height: '100%',
width: '100%',
},
contentContainer: {
padding: Sizing.t3,
paddingVertical: Sizing.t3,
paddingHorizontal: Sizing.t3,
},
search: {
backgroundColor: 'background-basic-color-1',
borderRadius: 40,
marginBottom: Sizing.t2,
},
})

View File

@ -1,15 +1,15 @@
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { NewsItem } from '@skolplattformen/embedded-api'
import React, { ReactNode } from 'react'
import { StyleService, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment'
import React, { ReactNode } from 'react'
import { Dimensions, Text, View } from 'react-native'
import { TouchableOpacity } from 'react-native-gesture-handler'
import { Layout, Sizing, Typography } from '../styles'
import { useChild } from './childContext.component'
import { Image } from './image.component'
import { RootStackParamList } from './navigation.component'
import { StyleService, useStyleSheet } from '@ui-kitten/components'
interface NewsListItemProps {
item: NewsItem
@ -66,15 +66,11 @@ const themedStyles = StyleService.create({
card: {
...Layout.flex.full,
...Layout.flex.row,
borderRadius: 2,
borderWidth: 1,
padding: Sizing.t5,
marginBottom: Sizing.t2,
borderRadius: 15,
paddingVertical: Sizing.t4,
paddingHorizontal: Sizing.t4,
marginBottom: Sizing.t3,
backgroundColor: 'background-basic-color-1',
borderColor: 'border-basic-color-3',
},
text: {
...Layout.flex.full,
@ -86,7 +82,6 @@ const themedStyles = StyleService.create({
},
subtitle: {
...Typography.fontSize.xs,
marginBottom: Sizing.t2,
color: 'text-hint-color',
},
@ -95,9 +90,9 @@ const themedStyles = StyleService.create({
color: 'text-basic-color',
},
image: {
borderRadius: 3,
width: 80,
height: 80,
marginRight: Sizing.t5,
borderRadius: 50,
width: 50,
height: 50,
marginRight: Sizing.t3,
},
})

View File

@ -1,10 +1,10 @@
import { Notification as NotificationType } from '@skolplattformen/embedded-api'
import { Card, StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment'
import React from 'react'
import { View } from 'react-native'
import { TouchableOpacity, View } from 'react-native'
import { Layout, Sizing, Typography } from '../styles'
import { ModalWebView } from './modalWebView.component'
import moment from 'moment'
interface NotificationProps {
item: NotificationType
@ -26,11 +26,9 @@ export const Notification = ({ item }: NotificationProps) => {
return (
<>
<Card
style={styles.card}
onPress={open}
header={(headerProps) => (
<View {...headerProps}>
<TouchableOpacity onPress={open}>
<View style={styles.card}>
<View>
<Text style={styles.title}>{item.sender}</Text>
<Text style={styles.subtitle}>
{item.category ? item.category : ''}
@ -38,10 +36,9 @@ export const Notification = ({ item }: NotificationProps) => {
{displayDate ? displayDate : ''}
</Text>
</View>
)}
>
<Text>{item.message}</Text>
</Card>
<Text>{item.message}</Text>
</View>
</TouchableOpacity>
{isOpen && (
<ModalWebView
url={item.url}
@ -56,13 +53,11 @@ export const Notification = ({ item }: NotificationProps) => {
const themedStyles = StyleService.create({
card: {
...Layout.flex.full,
borderRadius: 2,
borderWidth: 1,
marginBottom: Sizing.t2,
borderRadius: 15,
paddingVertical: Sizing.t4,
paddingHorizontal: Sizing.t4,
marginBottom: Sizing.t3,
backgroundColor: 'background-basic-color-1',
borderColor: 'border-basic-color-3',
},
title: {
...Typography.header,
@ -71,5 +66,6 @@ const themedStyles = StyleService.create({
subtitle: {
...Typography.fontSize.xs,
color: 'text-hint-color',
marginBottom: Sizing.t2,
},
})

View File

@ -1,14 +1,15 @@
import { useNotifications } from '@skolplattformen/api-hooks'
import { List } from '@ui-kitten/components'
import { List, StyleService, useStyleSheet } from '@ui-kitten/components'
import React from 'react'
import { StyleSheet } from 'react-native'
import { Sizing } from '../styles'
import { useChild } from './childContext.component'
import { Notification } from './notification.component'
export const NotificationsList = () => {
const styles = useStyleSheet(themedStyles)
const child = useChild()
const { data } = useNotifications(child)
return (
<List
style={styles.container}
@ -21,12 +22,13 @@ export const NotificationsList = () => {
)
}
const styles = StyleSheet.create({
const themedStyles = StyleService.create({
container: {
height: '100%',
width: '100%',
},
contentContainer: {
padding: Sizing.t3,
paddingHorizontal: Sizing.t3,
paddingVertical: Sizing.t3,
},
})

View File

@ -1,26 +1,33 @@
import { useNavigation } from '@react-navigation/native'
import {
Layout,
Text,
Button,
ButtonGroup,
TopNavigationAction,
TopNavigation,
StyleService,
Text,
useStyleSheet,
useTheme,
} from '@ui-kitten/components'
import React, { useState } from 'react'
import { StyleSheet, View } from 'react-native'
import { View } from 'react-native'
import { ScrollView, TouchableOpacity } from 'react-native-gesture-handler'
import RNRestart from 'react-native-restart'
import { SafeAreaView } from 'react-native-safe-area-context'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import { useLanguage } from '../hooks/useLanguage'
import { isRTL, LanguageService } from '../services/languageService'
import { Layout as LayoutStyle, Sizing } from '../styles'
import { translate, languages } from '../utils/translation'
import { BackIcon } from './icon.component'
import { SafeAreaViewContainer } from '../ui/safeAreaViewContainer.component'
import RNRestart from 'react-native-restart'
import { SafeAreaView } from '../ui/safeAreaView.component'
import { fontSize } from '../styles/typography'
import { languages, translate } from '../utils/translation'
import { CheckIcon } from './icon.component'
export const setLanguageRouteOptions = (): NativeStackNavigationOptions => ({
title: translate('language.changeLanguage'),
})
export const SetLanguage = () => {
const navigation = useNavigation()
const styles = useStyleSheet(themedStyles)
const colors = useTheme()
const currentLanguage = LanguageService.getLanguageCode()
@ -56,77 +63,66 @@ export const SetLanguage = () => {
const activeLanguages = languages.filter((language) => language.active)
return (
<SafeAreaView>
<SafeAreaViewContainer>
<TopNavigation
accessoryLeft={() => (
<TopNavigationAction icon={BackIcon} onPress={() => goBack()} />
)}
alignment="center"
title={translate('language.changeLanguage')}
/>
<SafeAreaView style={styles.container} edges={['bottom']}>
<ScrollView>
<View style={styles.content}>
<ScrollView>
<Layout style={styles.container}>
<View style={styles.languageList}>
{activeLanguages.map((language) => (
<TouchableOpacity
key={language.langCode}
style={styles.languageButton}
onPress={() => setSelectedLanguage(language.langCode)}
>
<Text style={styles.check}>
{isSelected(language.langCode) ? '✓' : ''}
</Text>
<Text>{language.languageName}</Text>
<Text style={styles.languageButtonSubtitle}>
{language.languageLocalName}
</Text>
</TouchableOpacity>
))}
</View>
</Layout>
</ScrollView>
<ButtonGroup style={styles.buttonGroup}>
<Button
onPress={() => saveLanguage()}
appearance="ghost"
status="primary"
disabled={currentLanguage === selectedLanguage}
style={styles.button}
size="medium"
>
{translate('language.changeLanguageButton')}
</Button>
</ButtonGroup>
<View style={styles.languageList}>
{activeLanguages.map((language) => (
<TouchableOpacity
key={language.langCode}
style={styles.languageButton}
onPress={() => setSelectedLanguage(language.langCode)}
>
<View>
<Text style={styles.languageButtonTitle}>
{language.languageLocalName}
</Text>
<Text style={styles.languageButtonSubtitle}>
{language.languageName}
</Text>
</View>
{isSelected(language.langCode) ? (
<CheckIcon
height={24}
width={24}
fill={colors['color-success-600']}
/>
) : null}
</TouchableOpacity>
))}
</View>
</View>
</SafeAreaViewContainer>
</ScrollView>
<ButtonGroup style={styles.buttonGroup}>
<Button
onPress={() => saveLanguage()}
appearance="ghost"
status="primary"
disabled={currentLanguage === selectedLanguage}
style={styles.button}
size="medium"
>
{translate('language.changeLanguageButton')}
</Button>
</ButtonGroup>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
const themedStyles = StyleService.create({
languageList: {
flex: 1,
alignSelf: 'stretch',
flexDirection: 'column',
marginTop: 40,
marginTop: 8,
},
icon: {
width: 30,
height: 30,
},
check: {
position: 'absolute',
left: -20,
color: 'green',
},
container: {
...LayoutStyle.mainAxis.center,
...LayoutStyle.crossAxis.flexEnd,
padding: Sizing.t5,
flex: 1,
backgroundColor: 'background-basic-color-2',
},
content: {
...LayoutStyle.center,
@ -137,12 +133,20 @@ const styles = StyleSheet.create({
buttonGroup: {
minHeight: 45,
marginTop: 20,
marginHorizontal: Sizing.t5,
},
languageButton: {
minHeight: 45,
marginBottom: 10,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
languageButtonTitle: {
...fontSize.lg,
},
languageButtonSubtitle: {
...fontSize.sm,
opacity: 0.4,
},
button: { ...LayoutStyle.flex.full },

View File

@ -0,0 +1,37 @@
import { Text, useTheme } from '@ui-kitten/components'
import React from 'react'
import { StyleSheet, View } from 'react-native'
import { fontSize } from '../styles/typography'
import { initials } from '../utils/peopleHelpers'
export type StudentAvatarProps = {
name?: string
color: string
}
export const StudentAvatar = ({ name, color }: StudentAvatarProps) => {
const colors = useTheme()
const bgColor = colors[`color-${color}-100`]
const textColor = colors[`color-${color}-900`]
return (
<View style={{ ...styles.container, backgroundColor: bgColor }}>
<Text style={{ ...styles.text, color: textColor }}>{initials(name)}</Text>
</View>
)
}
export const styles = StyleSheet.create({
container: {
height: 44,
width: 44,
borderRadius: 300,
alignItems: 'center',
justifyContent: 'center',
},
text: {
...fontSize.lg,
fontFamily: 'Poppins-Medium',
fontWeight: '500',
},
})

View File

@ -1,22 +1,22 @@
import { useMenu, useTimetable } from '@skolplattformen/api-hooks'
import { Child, MenuItem, TimetableEntry } from '@skolplattformen/embedded-api'
import {
List,
ListItem,
ViewPager,
Text,
TabBar,
Tab,
StyleService,
Tab,
TabBar,
Text,
useStyleSheet,
ViewPager,
} from '@ui-kitten/components'
import React, { useEffect, useState } from 'react'
import moment from 'moment'
import React, { useEffect, useState } from 'react'
import { View } from 'react-native'
import { useMenu, useTimetable } from '@skolplattformen/api-hooks'
import { TimetableEntry, Child, MenuItem } from '@skolplattformen/embedded-api'
import { LanguageService } from '../services/languageService'
import { Sizing, Typography } from '../styles'
import { translate } from '../utils/translation'
import { TransitionView } from './transitionView.component'
import { Typography, Sizing } from '../styles'
interface WeekProps {
child: Child
@ -174,7 +174,7 @@ export const Week = ({ child }: WeekProps) => {
const themedStyles = StyleService.create({
view: {
backgroundColor: 'background-basic-color-2',
backgroundColor: 'background-basic-color-1',
},
part: {
backgroundColor: 'transparent',
@ -186,7 +186,7 @@ const themedStyles = StyleService.create({
},
item: {
height: 45,
backgroundColor: 'background-basic-color-1',
backgroundColor: 'background-basic-color-2',
paddingHorizontal: 0,
borderRadius: 2,
margin: 2,

View File

@ -1,13 +1,14 @@
{
"color-primary-100": "#FDD3D4",
"color-primary-200": "#FBA7B3",
"color-primary-300": "#F47A97",
"color-primary-400": "#E95789",
"color-primary-500": "#DB2575",
"color-primary-600": "#BC1B72",
"color-primary-700": "#9D126B",
"color-primary-800": "#7F0B60",
"color-primary-900": "#690759",
"color-primary-50": "#FFECF9",
"color-primary-100": "#FEC9EF",
"color-primary-200": "#FD82DA",
"color-primary-300": "#FB3CC6",
"color-primary-400": "#EC04AB",
"color-primary-500": "#A60378",
"color-primary-600": "#880262",
"color-primary-700": "#6A024D",
"color-primary-800": "#4C0137",
"color-primary-900": "#2E0121",
"color-primary-transparent-100": "rgba(219, 37, 117, 0.08)",
"color-primary-transparent-200": "rgba(219, 37, 117, 0.16)",
"color-primary-transparent-300": "rgba(219, 37, 117, 0.24)",
@ -29,30 +30,21 @@
"color-success-transparent-400": "rgba(100, 165, 24, 0.32)",
"color-success-transparent-500": "rgba(100, 165, 24, 0.4)",
"color-success-transparent-600": "rgba(100, 165, 24, 0.48)",
"color-info-100": "#D1E5FE",
"color-info-200": "#A5C9FD",
"color-info-300": "#77AAFB",
"color-info-400": "#558EF7",
"color-info-500": "#1F62F2",
"color-info-600": "#164BD0",
"color-info-700": "#0F37AE",
"color-info-800": "#09268C",
"color-info-900": "#051A74",
"color-info-transparent-100": "rgba(31, 98, 242, 0.08)",
"color-info-transparent-200": "rgba(31, 98, 242, 0.16)",
"color-info-transparent-300": "rgba(31, 98, 242, 0.24)",
"color-info-transparent-400": "rgba(31, 98, 242, 0.32)",
"color-info-transparent-500": "rgba(31, 98, 242, 0.4)",
"color-info-transparent-600": "rgba(31, 98, 242, 0.48)",
"color-warning-100": "#FCF1CA",
"color-warning-200": "#F9E097",
"color-warning-300": "#EFC662",
"color-warning-400": "#E0A93B",
"color-warning-500": "#CC8204",
"color-warning-600": "#AF6902",
"color-warning-700": "#925202",
"color-warning-800": "#763D01",
"color-warning-900": "#612F00",
"color-info-100": "#CFE3FB",
"color-info-200": "#A1C5F8",
"color-info-300": "#6F9EEA",
"color-info-400": "#4A7AD5",
"color-info-500": "#184BBA",
"color-info-600": "#11399F",
"color-info-700": "#0C2A85",
"color-info-800": "#071D6B",
"color-info-900": "#041459",
"color-info-transparent-100": "rgba(24, 75, 186, 0.08)",
"color-info-transparent-200": "rgba(24, 75, 186, 0.16)",
"color-info-transparent-300": "rgba(24, 75, 186, 0.24)",
"color-info-transparent-400": "rgba(24, 75, 186, 0.32)",
"color-info-transparent-500": "rgba(24, 75, 186, 0.4)",
"color-info-transparent-600": "rgba(24, 75, 186, 0.48)",
"color-warning-transparent-100": "rgba(204, 130, 4, 0.08)",
"color-warning-transparent-200": "rgba(204, 130, 4, 0.16)",
"color-warning-transparent-300": "rgba(204, 130, 4, 0.24)",
@ -74,14 +66,12 @@
"color-danger-transparent-400": "rgba(186, 50, 127, 0.32)",
"color-danger-transparent-500": "rgba(186, 50, 127, 0.4)",
"color-danger-transparent-600": "rgba(186, 50, 127, 0.48)",
"background-basic-color-1": "#2E3137",
"background-basic-color-2": "#202225",
"background-basic-color-1": "#150A12",
"background-basic-color-2": "#030200",
"color-control-default": "#E5E7EB",
/* text colors */
"color-basic-800": "#DCDDDE",
"color-basic-600": "#DCDDDE",
"color-basic-500": "#8E9297",
/* basic button colors */
"color-basic-300": "#202020",
"color-basic-400": "gray"
"color-basic-default": "$color-primary-800",
"color-basic-focus": "$color-primary-700",
"color-basic-hover": "$color-primary-700",
"color-basic-active": "$color-primary-700",
"color-basic-text": "$color-primary-100"
}

View File

@ -1,13 +1,14 @@
{
"color-primary-100": "#FDD3D4",
"color-primary-200": "#FBA7B3",
"color-primary-300": "#F47A97",
"color-primary-400": "#E95789",
"color-primary-500": "#DB2575",
"color-primary-600": "#BC1B72",
"color-primary-700": "#9D126B",
"color-primary-800": "#7F0B60",
"color-primary-900": "#690759",
"color-primary-50": "#FFECF9",
"color-primary-100": "#FEC9EF",
"color-primary-200": "#FD82DA",
"color-primary-300": "#FB3CC6",
"color-primary-400": "#EC04AB",
"color-primary-500": "#A60378",
"color-primary-600": "#880262",
"color-primary-700": "#6A024D",
"color-primary-800": "#4C0137",
"color-primary-900": "#2E0121",
"color-primary-transparent-100": "rgba(219, 37, 117, 0.08)",
"color-primary-transparent-200": "rgba(219, 37, 117, 0.16)",
"color-primary-transparent-300": "rgba(219, 37, 117, 0.24)",
@ -29,21 +30,21 @@
"color-success-transparent-400": "rgba(100, 165, 24, 0.32)",
"color-success-transparent-500": "rgba(100, 165, 24, 0.4)",
"color-success-transparent-600": "rgba(100, 165, 24, 0.48)",
"color-info-100": "#D1E5FE",
"color-info-200": "#A5C9FD",
"color-info-300": "#77AAFB",
"color-info-400": "#558EF7",
"color-info-500": "#1F62F2",
"color-info-600": "#164BD0",
"color-info-700": "#0F37AE",
"color-info-800": "#09268C",
"color-info-900": "#051A74",
"color-info-transparent-100": "rgba(31, 98, 242, 0.08)",
"color-info-transparent-200": "rgba(31, 98, 242, 0.16)",
"color-info-transparent-300": "rgba(31, 98, 242, 0.24)",
"color-info-transparent-400": "rgba(31, 98, 242, 0.32)",
"color-info-transparent-500": "rgba(31, 98, 242, 0.4)",
"color-info-transparent-600": "rgba(31, 98, 242, 0.48)",
"color-info-100": "#C6EEF8",
"color-info-200": "#90D9F1",
"color-info-300": "#55AED5",
"color-info-400": "#2B7DAC",
"color-info-500": "#004475",
"color-info-600": "#003464",
"color-info-700": "#002754",
"color-info-800": "#001B43",
"color-info-900": "#001338",
"color-info-transparent-100": "rgba(0, 68, 117, 0.08)",
"color-info-transparent-200": "rgba(0, 68, 117, 0.16)",
"color-info-transparent-300": "rgba(0, 68, 117, 0.24)",
"color-info-transparent-400": "rgba(0, 68, 117, 0.32)",
"color-info-transparent-500": "rgba(0, 68, 117, 0.4)",
"color-info-transparent-600": "rgba(0, 68, 117, 0.48)",
"color-warning-100": "#FCF1CA",
"color-warning-200": "#F9E097",
"color-warning-300": "#EFC662",
@ -74,8 +75,12 @@
"color-danger-transparent-400": "rgba(186, 50, 127, 0.32)",
"color-danger-transparent-500": "rgba(186, 50, 127, 0.4)",
"color-danger-transparent-600": "rgba(186, 50, 127, 0.48)",
"color-basic-800": "#1F2937",
"color-basic-600": "#4B5563",
"color-basic-500": "#6B7280",
"color-basic-400": "#E4E9F2"
}
"background-basic-color-1": "#fff",
"background-basic-color-2": "$color-basic-200",
"text-hint-color": "#4B5466",
"color-basic-default": "$color-primary-50",
"color-basic-focus": "$color-primary-100",
"color-basic-hover": "$color-primary-100",
"color-basic-active": "$color-primary-100",
"color-basic-text": "$color-primary-800"
}

View File

@ -1,6 +1,7 @@
{
"strict": {
"border-radius": 50
"text-font-family": "Poppins",
"border-radius": 10
},
"components": {
"Button": {
@ -10,13 +11,13 @@
"mapping": {},
"variantGroups": {
"status": {
"primary": {
"backgroundColor": "blue"
"basic": {
"textColor": "$color-basic-text"
}
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,35 @@
import { DarkTheme, DefaultTheme, Theme } from '@react-navigation/native'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import { darkTheme, lightTheme } from './themes'
export const darkNavigationTheme: Theme = {
...DarkTheme,
colors: {
...DarkTheme.colors,
background: darkTheme['background-basic-color-2'],
border: darkTheme['background-basic-color-1'],
card: darkTheme['background-basic-color-1'],
primary: darkTheme['color-primary-400'],
text: '#ddd',
},
}
export const lightNavigationTheme: Theme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: lightTheme['background-basic-color-2'],
border: lightTheme['background-basic-color-1'],
card: lightTheme['background-basic-color-1'],
primary: lightTheme['color-primary-500'],
},
}
export const defaultStackStyling: NativeStackNavigationOptions = {
headerTitleStyle: {
fontFamily: 'Poppins-Medium',
},
headerBackTitleStyle: {
fontFamily: 'Poppins-Regular',
},
}

View File

@ -0,0 +1,12 @@
import * as eva from '@eva-design/eva'
import darkJsonTheme from './dark.json'
import lightJsonTheme from './light.json'
export const darkTheme = {
...eva.dark,
...darkJsonTheme,
}
export const lightTheme = {
...eva.light,
...lightJsonTheme,
}

View File

@ -1,9 +1,10 @@
/**
* @format
*/
import 'react-native-gesture-handler'
import { AppRegistry } from 'react-native'
import App from './App'
import { name as appName } from './app.json'
AppRegistry.registerComponent(appName, () => App)

View File

@ -351,7 +351,7 @@ PODS:
- React
- RNCAsyncStorage (1.15.2):
- React-Core
- RNCMaskedView (0.1.10):
- RNCMaskedView (0.1.11):
- React
- RNDateTimePicker (3.4.3):
- React-Core
@ -359,8 +359,38 @@ PODS:
- React-Core
- RNLocalize (2.0.3):
- React-Core
- RNScreens (2.18.1):
- RNReanimated (2.2.0):
- DoubleConversion
- FBLazyVector
- FBReactNativeSpec
- glog
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React
- React-callinvoker
- React-Core
- React-Core/DevSupport
- React-Core/RCTWebSocket
- React-CoreModules
- React-cxxreact
- React-jsi
- React-jsiexecutor
- React-jsinspector
- React-RCTActionSheet
- React-RCTAnimation
- React-RCTBlob
- React-RCTImage
- React-RCTLinking
- React-RCTNetwork
- React-RCTSettings
- React-RCTText
- React-RCTVibration
- ReactCommon/turbomodule/core
- Yoga
- RNScreens (3.3.0):
- React-Core
- React-RCTImage
- RNSVG (12.1.0):
- React
- Toast (4.0.0)
@ -433,6 +463,7 @@ DEPENDENCIES:
- "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
@ -535,6 +566,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-gesture-handler"
RNLocalize:
:path: "../node_modules/react-native-localize"
RNReanimated:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
RNSVG:
@ -547,7 +580,7 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: 7b423f9e248eae65987838148c36eec1dbfe0b53
FBReactNativeSpec: 04fc66100bad544f2d734662e11d7d631249fa0b
FBReactNativeSpec: 313b66e17294041415f72c26996e9670a9f07a59
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
@ -591,11 +624,12 @@ SPEC CHECKSUMS:
ReactCommon: bedc99ed4dae329c4fcf128d0c31b9115e5365ca
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
RNCAsyncStorage: 9b7605e899f9acb2fba33e87952c529731265453
RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNDateTimePicker: d943800c936fb01c352fcfb70439550d2cb57092
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
RNLocalize: 99e59cad311ca1b6872b1764514009416ccba03d
RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
RNReanimated: 9c13c86454bfd54dab7505c1a054470bfecd2563
RNScreens: bf59f17fbf001f1025243eeed5f19419d3c11ef2
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
Yoga: a7de31c64fe738607e7a3803e3f591a4b1df7393

View File

@ -8,17 +8,35 @@
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* appTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* appTests.m */; };
04B5A89762F9430A902416B4 /* Poppins-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3CBFE8DBE8994C1FAF939519 /* Poppins-MediumItalic.ttf */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
230E5925A9044F679B2F7C39 /* Poppins-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7AF5677EA52D44EE97668E7A /* Poppins-Medium.ttf */; };
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2DC4DBF14540481ABF14857A /* Poppins-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9A9C27037F0F4AF2A4CBAE78 /* Poppins-ExtraBold.ttf */; };
2DCD954D1E0B4F2C00145EB5 /* appTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* appTests.m */; };
417D579C3DC24A9684D24EDD /* Poppins-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 00FDE4C2522044DAAD866D5F /* Poppins-BlackItalic.ttf */; };
41DE97CF96674977BC052462 /* Poppins-SemiBoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A9CB7679337840D3BD256A13 /* Poppins-SemiBoldItalic.ttf */; };
4E01D1C8DD5749C8953D3BE5 /* Poppins-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 661AE05493ED4FE780C32EF6 /* Poppins-Bold.ttf */; };
4F931CB3182F40F580F357FF /* Poppins-ThinItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E251C7BB03F74441B4357419 /* Poppins-ThinItalic.ttf */; };
50AAEBD19BD24B129801C393 /* Poppins-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 977D264ECA05485EA89A2F13 /* Poppins-Italic.ttf */; };
5257E7B8420740A2862BEEB0 /* Poppins-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8E2BDC4163F1467E94E5D34C /* Poppins-BoldItalic.ttf */; };
6D069850985349ABB76BDD0A /* Poppins-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B1A304CF782943E19F93DFD6 /* Poppins-Black.ttf */; };
71436C48CDF348BE904103E9 /* Poppins-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 231B760691854EBCA7ECD80E /* Poppins-Light.ttf */; };
7B94D8768C6340958F2EEFFD /* Poppins-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C9AC377D6B7744ECBBEA0A8A /* Poppins-ExtraLight.ttf */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
836E1F3164D8497F8C51847A /* Poppins-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7CEBAD12E8E5471AA962262A /* Poppins-LightItalic.ttf */; };
8F8E6DB2A0AB4DF3A5ED51E7 /* Poppins-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 920F53F06E0B433DB798AC45 /* Poppins-SemiBold.ttf */; };
9FA2A398A0264369AD50123F /* Poppins-ExtraBoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9F1539AF1544412D9662D264 /* Poppins-ExtraBoldItalic.ttf */; };
9FC2C87C76F74B609BA3709E /* Poppins-ExtraLightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9420B3EA5C884AFFADCAFB4C /* Poppins-ExtraLightItalic.ttf */; };
9FDEB3BC9BEB0D9B20C40FFA /* libPods-app-appTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 198E5E1047B7B7C1FE9480E3 /* libPods-app-appTests.a */; };
A74B9EB17CB0D9069DBDEC11 /* libPods-app.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A849643D470B360BB9710A2 /* libPods-app.a */; };
AC5E863985C04D72B5806B58 /* Poppins-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 02B78F6C72354B2D8171239D /* Poppins-Thin.ttf */; };
B9CA13426DF0582117265C94 /* libPods-app-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 209E1A9D464732CA3D5436BA /* libPods-app-tvOS.a */; };
BB34E03413EB4CDFA59766B1 /* Poppins-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EB6EB5293E4C48098CBD53C2 /* Poppins-Regular.ttf */; };
F8EEF49F61D796445B439296 /* libPods-app-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD654FF33034F72E23F45E0 /* libPods-app-tvOSTests.a */; };
/* End PBXBuildFile section */
@ -44,6 +62,8 @@
00E356EE1AD99517003FC87E /* appTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = appTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* appTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = appTests.m; sourceTree = "<group>"; };
00FDE4C2522044DAAD866D5F /* Poppins-BlackItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-BlackItalic.ttf"; path = "../assets/fonts/Poppins-BlackItalic.ttf"; sourceTree = "<group>"; };
02B78F6C72354B2D8171239D /* Poppins-Thin.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Thin.ttf"; path = "../assets/fonts/Poppins-Thin.ttf"; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = app.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = app/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = app/AppDelegate.m; sourceTree = "<group>"; };
@ -53,18 +73,34 @@
198E5E1047B7B7C1FE9480E3 /* libPods-app-appTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-app-appTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
1A849643D470B360BB9710A2 /* libPods-app.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-app.a"; sourceTree = BUILT_PRODUCTS_DIR; };
209E1A9D464732CA3D5436BA /* libPods-app-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-app-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
231B760691854EBCA7ECD80E /* Poppins-Light.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Light.ttf"; path = "../assets/fonts/Poppins-Light.ttf"; sourceTree = "<group>"; };
2D02E47B1E0B4A5D006451C7 /* app-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "app-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2D02E4901E0B4A5D006451C7 /* app-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "app-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
3CBFE8DBE8994C1FAF939519 /* Poppins-MediumItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-MediumItalic.ttf"; path = "../assets/fonts/Poppins-MediumItalic.ttf"; sourceTree = "<group>"; };
4F9213F90B49965FDCF003FA /* Pods-app-appTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-appTests.release.xcconfig"; path = "Target Support Files/Pods-app-appTests/Pods-app-appTests.release.xcconfig"; sourceTree = "<group>"; };
55AC07BDE5542A03F6AD2FE2 /* Pods-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app.release.xcconfig"; path = "Target Support Files/Pods-app/Pods-app.release.xcconfig"; sourceTree = "<group>"; };
64A4BC0C882E097B17B89CAB /* Pods-app-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-app-tvOSTests/Pods-app-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
661AE05493ED4FE780C32EF6 /* Poppins-Bold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Bold.ttf"; path = "../assets/fonts/Poppins-Bold.ttf"; sourceTree = "<group>"; };
78E0CED54136BD6995951328 /* Pods-app-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-tvOS.release.xcconfig"; path = "Target Support Files/Pods-app-tvOS/Pods-app-tvOS.release.xcconfig"; sourceTree = "<group>"; };
7AF5677EA52D44EE97668E7A /* Poppins-Medium.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Medium.ttf"; path = "../assets/fonts/Poppins-Medium.ttf"; sourceTree = "<group>"; };
7CEBAD12E8E5471AA962262A /* Poppins-LightItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-LightItalic.ttf"; path = "../assets/fonts/Poppins-LightItalic.ttf"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = app/LaunchScreen.storyboard; sourceTree = "<group>"; };
866817BF8B562CD61F42398B /* Pods-app-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-app-tvOSTests/Pods-app-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
8E2BDC4163F1467E94E5D34C /* Poppins-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-BoldItalic.ttf"; path = "../assets/fonts/Poppins-BoldItalic.ttf"; sourceTree = "<group>"; };
920F53F06E0B433DB798AC45 /* Poppins-SemiBold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-SemiBold.ttf"; path = "../assets/fonts/Poppins-SemiBold.ttf"; sourceTree = "<group>"; };
9420B3EA5C884AFFADCAFB4C /* Poppins-ExtraLightItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-ExtraLightItalic.ttf"; path = "../assets/fonts/Poppins-ExtraLightItalic.ttf"; sourceTree = "<group>"; };
977D264ECA05485EA89A2F13 /* Poppins-Italic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Italic.ttf"; path = "../assets/fonts/Poppins-Italic.ttf"; sourceTree = "<group>"; };
9A9C27037F0F4AF2A4CBAE78 /* Poppins-ExtraBold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-ExtraBold.ttf"; path = "../assets/fonts/Poppins-ExtraBold.ttf"; sourceTree = "<group>"; };
9F1539AF1544412D9662D264 /* Poppins-ExtraBoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-ExtraBoldItalic.ttf"; path = "../assets/fonts/Poppins-ExtraBoldItalic.ttf"; sourceTree = "<group>"; };
A9CB7679337840D3BD256A13 /* Poppins-SemiBoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-SemiBoldItalic.ttf"; path = "../assets/fonts/Poppins-SemiBoldItalic.ttf"; sourceTree = "<group>"; };
AB8B9EC2CC8BC79836F11661 /* Pods-app-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-app-tvOS/Pods-app-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
B1A304CF782943E19F93DFD6 /* Poppins-Black.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Black.ttf"; path = "../assets/fonts/Poppins-Black.ttf"; sourceTree = "<group>"; };
C9AC377D6B7744ECBBEA0A8A /* Poppins-ExtraLight.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-ExtraLight.ttf"; path = "../assets/fonts/Poppins-ExtraLight.ttf"; sourceTree = "<group>"; };
D9ABD588946E114F0E0A649D /* Pods-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app.debug.xcconfig"; path = "Target Support Files/Pods-app/Pods-app.debug.xcconfig"; sourceTree = "<group>"; };
DAD654FF33034F72E23F45E0 /* libPods-app-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-app-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DE49AE0B25BD2EF3496BCE37 /* Pods-app-appTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-appTests.debug.xcconfig"; path = "Target Support Files/Pods-app-appTests/Pods-app-appTests.debug.xcconfig"; sourceTree = "<group>"; };
E251C7BB03F74441B4357419 /* Poppins-ThinItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-ThinItalic.ttf"; path = "../assets/fonts/Poppins-ThinItalic.ttf"; sourceTree = "<group>"; };
EB6EB5293E4C48098CBD53C2 /* Poppins-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Poppins-Regular.ttf"; path = "../assets/fonts/Poppins-Regular.ttf"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
@ -180,6 +216,7 @@
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
678C13018B6095451BF5FE91 /* Pods */,
86DE8D5EB35F4504B427A63A /* Resources */,
);
indentWidth = 2;
sourceTree = "<group>";
@ -197,6 +234,32 @@
name = Products;
sourceTree = "<group>";
};
86DE8D5EB35F4504B427A63A /* Resources */ = {
isa = PBXGroup;
children = (
B1A304CF782943E19F93DFD6 /* Poppins-Black.ttf */,
00FDE4C2522044DAAD866D5F /* Poppins-BlackItalic.ttf */,
661AE05493ED4FE780C32EF6 /* Poppins-Bold.ttf */,
8E2BDC4163F1467E94E5D34C /* Poppins-BoldItalic.ttf */,
9A9C27037F0F4AF2A4CBAE78 /* Poppins-ExtraBold.ttf */,
9F1539AF1544412D9662D264 /* Poppins-ExtraBoldItalic.ttf */,
C9AC377D6B7744ECBBEA0A8A /* Poppins-ExtraLight.ttf */,
9420B3EA5C884AFFADCAFB4C /* Poppins-ExtraLightItalic.ttf */,
977D264ECA05485EA89A2F13 /* Poppins-Italic.ttf */,
231B760691854EBCA7ECD80E /* Poppins-Light.ttf */,
7CEBAD12E8E5471AA962262A /* Poppins-LightItalic.ttf */,
7AF5677EA52D44EE97668E7A /* Poppins-Medium.ttf */,
3CBFE8DBE8994C1FAF939519 /* Poppins-MediumItalic.ttf */,
EB6EB5293E4C48098CBD53C2 /* Poppins-Regular.ttf */,
920F53F06E0B433DB798AC45 /* Poppins-SemiBold.ttf */,
A9CB7679337840D3BD256A13 /* Poppins-SemiBoldItalic.ttf */,
02B78F6C72354B2D8171239D /* Poppins-Thin.ttf */,
E251C7BB03F74441B4357419 /* Poppins-ThinItalic.ttf */,
);
name = Resources;
path = "";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -349,6 +412,24 @@
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
6D069850985349ABB76BDD0A /* Poppins-Black.ttf in Resources */,
417D579C3DC24A9684D24EDD /* Poppins-BlackItalic.ttf in Resources */,
4E01D1C8DD5749C8953D3BE5 /* Poppins-Bold.ttf in Resources */,
5257E7B8420740A2862BEEB0 /* Poppins-BoldItalic.ttf in Resources */,
2DC4DBF14540481ABF14857A /* Poppins-ExtraBold.ttf in Resources */,
9FA2A398A0264369AD50123F /* Poppins-ExtraBoldItalic.ttf in Resources */,
7B94D8768C6340958F2EEFFD /* Poppins-ExtraLight.ttf in Resources */,
9FC2C87C76F74B609BA3709E /* Poppins-ExtraLightItalic.ttf in Resources */,
50AAEBD19BD24B129801C393 /* Poppins-Italic.ttf in Resources */,
71436C48CDF348BE904103E9 /* Poppins-Light.ttf in Resources */,
836E1F3164D8497F8C51847A /* Poppins-LightItalic.ttf in Resources */,
230E5925A9044F679B2F7C39 /* Poppins-Medium.ttf in Resources */,
04B5A89762F9430A902416B4 /* Poppins-MediumItalic.ttf in Resources */,
BB34E03413EB4CDFA59766B1 /* Poppins-Regular.ttf in Resources */,
8F8E6DB2A0AB4DF3A5ED51E7 /* Poppins-SemiBold.ttf in Resources */,
41DE97CF96674977BC052462 /* Poppins-SemiBoldItalic.ttf in Resources */,
AC5E863985C04D72B5806B58 /* Poppins-Thin.ttf in Resources */,
4F931CB3182F40F580F357FF /* Poppins-ThinItalic.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -894,6 +975,7 @@
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -954,6 +1036,7 @@
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

View File

@ -38,7 +38,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
@ -51,7 +51,7 @@
<key>NSCalendarsUsageDescription</key>
<string>This app can add calendar events</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<string/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
@ -67,5 +67,26 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIAppFonts</key>
<array>
<string>Poppins-Black.ttf</string>
<string>Poppins-BlackItalic.ttf</string>
<string>Poppins-Bold.ttf</string>
<string>Poppins-BoldItalic.ttf</string>
<string>Poppins-ExtraBold.ttf</string>
<string>Poppins-ExtraBoldItalic.ttf</string>
<string>Poppins-ExtraLight.ttf</string>
<string>Poppins-ExtraLightItalic.ttf</string>
<string>Poppins-Italic.ttf</string>
<string>Poppins-Light.ttf</string>
<string>Poppins-LightItalic.ttf</string>
<string>Poppins-Medium.ttf</string>
<string>Poppins-MediumItalic.ttf</string>
<string>Poppins-Regular.ttf</string>
<string>Poppins-SemiBold.ttf</string>
<string>Poppins-SemiBoldItalic.ttf</string>
<string>Poppins-Thin.ttf</string>
<string>Poppins-ThinItalic.ttf</string>
</array>
</dict>
</plist>

View File

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -16,41 +17,30 @@
<rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Skolplattformen" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
<rect key="frame" x="0.0" y="131" width="414" height="27.666666666666657"/>
<constraints>
<constraint firstAttribute="height" constant="27.5" id="XcH-N0-h20"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="32"/>
<color key="textColor" systemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="skolplattformen-logga-original" translatesAutoresizingMaskIntoConstraints="NO" id="TKh-fJ-S9X">
<rect key="frame" x="44" y="293" width="340" height="340"/>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="skolplattformen-logga-original" translatesAutoresizingMaskIntoConstraints="NO" id="TKh-fJ-S9X">
<rect key="frame" x="-147" y="54" width="819" height="819"/>
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="default"/>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="122-lw-Ul7"/>
<constraint firstItem="TKh-fJ-S9X" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="1JX-HH-pzz"/>
<constraint firstItem="TKh-fJ-S9X" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="44" id="6bf-fh-uS6"/>
<constraint firstItem="TKh-fJ-S9X" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="8Gr-KZ-pEa"/>
<constraint firstItem="MN2-I3-ftu" firstAttribute="top" secondItem="Bcu-3y-fUS" secondAttribute="top" constant="87" id="PVH-eA-1yy"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="trailing" secondItem="MN2-I3-ftu" secondAttribute="trailing" constant="14" id="TcS-As-BCG"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="TKh-fJ-S9X" secondAttribute="bottom" constant="259" id="pzW-T6-bKj"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="52" y="374.66266866566718"/>
<point key="canvasLocation" x="51.86915887850467" y="374.51403887688986"/>
</scene>
</scenes>
<resources>
<image name="skolplattformen-logga-original" width="1210" height="1182"/>
<systemColor name="darkTextColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View File

@ -12,6 +12,7 @@ const MetroConfig = require('@ui-kitten/metro-config')
*/
const evaConfig = {
evaPackage: '@eva-design/eva',
customMappingPath: './design/mapping.json',
}
module.exports = MetroConfig.create(evaConfig, {

View File

@ -22,7 +22,7 @@
"@react-native-community/blur": "3.6.0",
"@react-native-community/cookies": "5.0.1",
"@react-native-community/datetimepicker": "3.4.3",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/masked-view": "^0.1.11",
"@react-navigation/bottom-tabs": "5.11.9",
"@react-navigation/native": "5.9.4",
"@react-navigation/stack": "5.14.4",
@ -47,13 +47,14 @@
"react-native-appearance": "^0.3.4",
"react-native-calendar-events": "2.2.0",
"react-native-fix-image": "2.1.0",
"react-native-gesture-handler": "1.10.3",
"react-native-gesture-handler": "^1.10.3",
"react-native-localize": "^2.0.2",
"react-native-markdown-display": "7.0.0-alpha.2",
"react-native-modal-datetime-picker": "9.2.0",
"react-native-reanimated": "^2.2.0",
"react-native-restart": "^0.0.22",
"react-native-safe-area-context": "3.2.0",
"react-native-screens": "2.18.1",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.3.0",
"react-native-simple-toast": "1.1.3",
"react-native-svg": "12.1.0",
"react-native-svg-transformer": "0.14.3",
@ -61,7 +62,7 @@
"react-native-typography": "1.4.1",
"react-native-webview": "11.4.2",
"react-native-weekly-calendar": "^0.2.0",
"rn-actionsheet-module": "https://github.com/viktorlarsson/rn-actionsheet-module",
"rn-actionsheet-module": "^1.0.3",
"use-async-storage": "1.2.0",
"yup": "0.32.9"
},
@ -70,8 +71,8 @@
"@babel/runtime": "^7.13.10",
"@react-native-community/eslint-config": "^2.0.0",
"@testing-library/jest-native": "^4.0.1",
"@testing-library/react-hooks": "^5.1.1",
"@testing-library/react-native": "7.1.0",
"@testing-library/react-hooks": "^7.0.0",
"@testing-library/react-native": "7.2.0",
"@types/i18n-js": "^3.8.0",
"@types/jest": "^26.0.22",
"@types/jsuri": "^1.3.30",

View File

@ -0,0 +1,3 @@
module.exports = {
assets: ['./assets/fonts']
}

View File

@ -1,7 +1,7 @@
import 'react-native-gesture-handler/jestSetup'
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock'
import moment from 'moment'
import 'moment/locale/sv'
import 'react-native-gesture-handler/jestSetup'
moment.locale('sv')
@ -9,3 +9,13 @@ jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage)
// Silence useNativeDriver error
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper')
jest.mock('react-native-reanimated', () => {
const Reanimated = require('react-native-reanimated/mock')
// The mock for `call` immediately calls the callback which is incorrect
// So we override it with a no-op
Reanimated.default.call = () => {}
return Reanimated
})

View File

@ -30,13 +30,14 @@ export const aspectRatio = (
}
}
type Layout = 't1' | 't2' | 't3' | 't4' | 't5'
type Layout = 't1' | 't2' | 't3' | 't4' | 't5' | 't6'
export const layout: Record<Layout, number> = {
t1: 4,
t2: 8,
t3: 12,
t4: 16,
t5: 20,
t6: 30,
}
/** 4px */
@ -49,3 +50,5 @@ export const t3 = layout.t3
export const t4 = layout.t4
/** 20px */
export const t5 = layout.t5
/** 30px */
export const t6 = layout.t6

View File

@ -30,7 +30,7 @@ export const fontWeight: Record<FontWeight, TextStyle> = {
},
bold: {
...systemWeights.bold,
},
}
}
export const header: TextStyle = {

View File

@ -19,7 +19,7 @@
"bankid": {
"OpenManually": "Öppna BankID manuellt",
"OpenOnAnotherDevice": "Öppna BankID på en annan enhet",
"OpenOnThisDevice": "Öppna BankID på denna enhet",
"OpenOnThisDevice": "Logga in med BankID",
"Waiting": "Väntar på BankID…"
},
"chooseLoginMethod": "Välj inloggningsmetod",

View File

@ -1,6 +1,7 @@
import { StyleService, useStyleSheet } from '@ui-kitten/components'
import React from 'react'
import { SafeAreaView as RNSafeAreaView, ViewProps } from 'react-native'
import { ViewProps } from 'react-native'
import { SafeAreaView as RNSafeAreaView } from 'react-native-safe-area-context'
import { Layout } from '../styles'
export const SafeAreaView: React.FC<ViewProps> = ({ children }) => {
@ -12,6 +13,6 @@ export const SafeAreaView: React.FC<ViewProps> = ({ children }) => {
const themedStyles = StyleService.create({
safeArea: {
...Layout.flex.full,
backgroundColor: 'background-basic-color-1',
backgroundColor: 'background-basic-color-2',
},
})

View File

@ -1,6 +1,7 @@
import {
fullName,
guardians,
initials,
sortByFirstName,
studentName,
} from '../peopleHelpers'
@ -72,3 +73,13 @@ describe('#guardians', () => {
).toEqual('Loras Eriksson, Margaery Eriksson')
})
})
describe('#initials', () => {
test('should extract initials from name', () => {
expect(initials('Namn Namnsson')).toEqual('Na')
expect(initials('Nisse Namnsson')).toEqual('Ni')
})
test('handles undefined name', () => {
expect(initials(undefined)).toBeUndefined()
})
})

View File

@ -1,9 +0,0 @@
export const studentName = (name) => name?.replace(/\s?\(\w+\)$/, '')
export const sortByFirstName = (data) =>
data.sort((a, b) => a.firstname.localeCompare(b.firstname))
export const guardians = (data) =>
sortByFirstName(data).map(fullName).join(', ')
export const fullName = (person) => `${person.firstname} ${person.lastname}`

View File

@ -0,0 +1,16 @@
import { Guardian } from '@skolplattformen/embedded-api'
export const studentName = (name?: string) => name?.replace(/\s?\(\w+\)$/, '')
export const sortByFirstName = (data: Guardian[]) =>
data.sort((a, b) => a.firstname.localeCompare(b.firstname))
export const guardians = (data: Guardian[]) =>
sortByFirstName(data).map(fullName).join(', ')
export const fullName = (person: Guardian) =>
`${person.firstname} ${person.lastname}`
export const initials = (name?: string) => {
return name?.slice(0, 2)
}

View File

@ -173,6 +173,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
"@babel/helper-plugin-utils@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
"@babel/helper-remap-async-to-generator@^7.13.0":
version "7.13.0"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
@ -546,6 +551,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-object-assign@^7.10.4":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.14.5.tgz#62537d54b6d85de04f4df48bfdba2eebff17b760"
integrity sha512-lvhjk4UN9xJJYB1mI5KC0/o1D5EcJXdbhVe+4fSk08D6ZN+iuAIs7LJC+71h8av9Ew4+uRq9452v9R93SFmQlQ==
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-object-super@^7.0.0":
version "7.12.13"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7"
@ -1360,10 +1372,10 @@
resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc"
integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ==
"@react-native-community/masked-view@0.1.10":
version "0.1.10"
resolved "https://registry.yarnpkg.com/@react-native-community/masked-view/-/masked-view-0.1.10.tgz#5dda643e19e587793bc2034dd9bf7398ad43d401"
integrity sha512-rk4sWFsmtOw8oyx8SD3KSvawwaK7gRBSEIy2TAwURyGt+3TizssXP1r8nx3zY+R7v2vYYHXZ+k2/GULAT/bcaQ==
"@react-native-community/masked-view@^0.1.11":
version "0.1.11"
resolved "https://registry.yarnpkg.com/@react-native-community/masked-view/-/masked-view-0.1.11.tgz#2f4c6e10bee0786abff4604e39a37ded6f3980ce"
integrity sha512-rQfMIGSR/1r/SyN87+VD8xHHzDYeHaJq6elOSCAD+0iLagXkSI2pfA0LmSXP21uw5i3em7GkkRjfJ8wpqWXZNw==
"@react-native/assets@1.0.0":
version "1.0.0"
@ -1583,22 +1595,21 @@
ramda "^0.26.1"
redent "^2.0.0"
"@testing-library/react-hooks@^5.1.1":
version "5.1.2"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-5.1.2.tgz#36e359d992bb652a9885c6fa9aa394639cbe8dd3"
integrity sha512-jwhtDYZ5gQUIX8cmVCVdtwNvuF5EiCOWjokRlTV+o/V0GdtRZDykUllL1OXq5PS4+J33wGLNQeeWzEHcWrH7tg==
"@testing-library/react-hooks@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-7.0.0.tgz#dd6d37a7e018f147a3b9153137f10e013be8472b"
integrity sha512-WFBGH8DWdIGGBHt6PBtQPe2v4Kbj9vQ1sQ9qLBTmwn1PNggngint4MTE/IiWCYhPbyTW3oc/7X62DObMn/AjQQ==
dependencies:
"@babel/runtime" "^7.12.5"
"@types/react" ">=16.9.0"
"@types/react-dom" ">=16.9.0"
"@types/react-test-renderer" ">=16.9.0"
filter-console "^0.1.1"
react-error-boundary "^3.1.0"
"@testing-library/react-native@7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-7.1.0.tgz#6b168aac21522c8a5175461b350336fd79612ac9"
integrity sha512-ljVM9KZqG7BT/NFN6CHzdF6MNmM28+k7MEybFJ7FW1wVrhpiY4+hU9ypZ+hboO+MG3KpE2aFBzP4od3gu+Zzdg==
"@testing-library/react-native@7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-7.2.0.tgz#e5ec5b0974e4e5f525f8057563417d1e9f820d96"
integrity sha512-rDKzJjAAeGgyoJT0gFQiMsIL09chdWcwZyYx6WZHMgm2c5NDqY52hUuyTkzhqddMYWmSRklFphSg7B2HX+246Q==
dependencies:
pretty-format "^26.0.1"
@ -4007,11 +4018,6 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
filter-console@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/filter-console/-/filter-console-0.1.1.tgz#6242be28982bba7415bcc6db74a79f4a294fa67c"
integrity sha512-zrXoV1Uaz52DqPs+qEwNJWJFAWZpYJ47UNmpN9q4j+/EYsz85uV0DC9k8tRND5kYmoVzL0W+Y75q4Rg8sRJCdg==
filter-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
@ -6671,7 +6677,7 @@ mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
mockdate@^3.0.5:
mockdate@^3.0.2, mockdate@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb"
integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==
@ -7594,7 +7600,7 @@ react-native-fix-image@2.1.0:
resolved "https://registry.yarnpkg.com/react-native-fix-image/-/react-native-fix-image-2.1.0.tgz#a4677b91529be926544775faf736df6af8c4743c"
integrity sha512-qn4xItNSKfwlSkMHgxH9cusUQuk5Lhag9aHqL9ESxnCDUDwqS6rsWuOYt/JlncaKhsCc9cANFomCLlY8+Ffuaw==
react-native-gesture-handler@1.10.3:
react-native-gesture-handler@^1.10.3:
version "1.10.3"
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz#942bbf2963bbf49fa79593600ee9d7b5dab3cfc0"
integrity sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw==
@ -7632,20 +7638,30 @@ react-native-modal-datetime-picker@9.2.0:
dependencies:
prop-types "^15.7.2"
react-native-reanimated@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz#a6412c56b4e591d1f00fac949f62d0c72c357c78"
integrity sha512-lOJDd+5w1gY6DHGXG2jD1dsjzQmXQ2699HUc3IztvI2WP4zUT+UAA+zSG+5JiBS5DUnTL8YhhkmUQmr1KNGO5w==
dependencies:
"@babel/plugin-transform-object-assign" "^7.10.4"
fbjs "^3.0.0"
mockdate "^3.0.2"
string-hash-64 "^1.0.3"
react-native-restart@^0.0.22:
version "0.0.22"
resolved "https://registry.yarnpkg.com/react-native-restart/-/react-native-restart-0.0.22.tgz#81fcb7f31e35951d85410c68b9556acf3ab88705"
integrity sha512-XwCqAMAKsO8yCM3xACPFKvkDQZe41lcavOuO0gUEu803IuTLtciualCq/qs83ryRDCDh1jkXYRqFjsGjLMCN3Q==
react-native-safe-area-context@3.2.0:
react-native-safe-area-context@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.2.0.tgz#06113c6b208f982d68ab5c3cebd199ca93db6941"
integrity sha512-k2Nty4PwSnrg9HwrYeeE+EYqViYJoOFwEy9LxL5RIRfoqxAq/uQXNGwpUg2/u4gnKpBbEPa9eRh15KKMe/VHkA==
react-native-screens@2.18.1:
version "2.18.1"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.18.1.tgz#47b9991c6f762d00d0ed3233e5283d523e859885"
integrity sha512-r5WZLpmx2hHjC1RgMdPq5YpSU9tEhBpUaZ5M1SUtNIONyiLqQVxabhRCINdebIk4depJiIl7yw2Q85zJyeX6fw==
react-native-screens@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.3.0.tgz#d4464a96620b85d09e46bd6865b5f48456c244f0"
integrity sha512-ni11jC6I9cFVXdLIDwkgafDHw/STXUNzkR5Fx3w8Wikdzi8gfTEan2kiOm7aS42d2F/LXddZ6i74Z2em0L6LPQ==
react-native-simple-toast@1.1.3:
version "1.1.3"
@ -8106,9 +8122,10 @@ rimraf@~2.6.2:
dependencies:
glob "^7.1.3"
"rn-actionsheet-module@https://github.com/viktorlarsson/rn-actionsheet-module":
rn-actionsheet-module@^1.0.3:
version "1.0.3"
resolved "https://github.com/viktorlarsson/rn-actionsheet-module#44ae59bff1b61177b0e63d73383bce4582008b47"
resolved "https://registry.yarnpkg.com/rn-actionsheet-module/-/rn-actionsheet-module-1.0.3.tgz#803857999b7a74df76eebbb36910e890c9527071"
integrity sha512-wm+VqcGEfmf5XcnyH7g98jqaAqj0EyjqaN1hIfip2qO/yMkg+ZX2gfus2kLJrvXRfEk9Rax40TnkzOEt6My5tA==
rsvp@^4.8.4:
version "4.8.5"
@ -8596,6 +8613,11 @@ strict-uri-encode@^2.0.0:
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
string-hash-64@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string-hash-64/-/string-hash-64-1.0.3.tgz#0deb56df58678640db5c479ccbbb597aaa0de322"
integrity sha512-D5OKWKvDhyVWWn2x5Y9b+37NUllks34q1dCDhk/vYcso9fmhs+Tl3KR/gE4v5UNj2UA35cnX4KdVVGkG1deKqw==
string-length@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837"

View File

@ -63,14 +63,14 @@ const Banner = (): JSX.Element => {
</div>
<H1>{intl.formatMessage({ id: 'general.title' })}</H1>
<p>{intl.formatMessage({ id: 'general.description' })}</p>
{!!intl.formatMessage({ id: 'general.flashtitle' }) && (
{/*intl.formatMessage({ id: 'general.flashtitle' }) && (
<div className="mt-5">
<h2 className="mb-4 text-2xl font-bold leading-tight text-gray-800 dark:text-white md:text-4xl">
{intl.formatMessage({ id: 'general.flashtitle' })}
</h2>
<p>{intl.formatMessage({ id: 'general.flashtext' })}</p>
</div>
)}
)*/}
<p className="flex items-center py-4 sm:flex-row space-x-2 lg:space-x-4">
<Link.External
className="inline-block"

View File

@ -7,6 +7,8 @@ const team = [
{ name: 'Johan Öbrink', twitter: 'johanobrink' },
{ name: 'Rickard Natt och Dag', twitter: 'rnattochdag' },
{ name: 'Viktor Sarström', twitter: 'viktorsarstrom' },
{ name: 'Kajetan Kazimierczak', twitter: 'kajetanek' },
{ name: 'Jonathan Edenström', twitter: 'edenstroem' },
{ name: 'Öppna skolplattformen', twitter: 'oppnaskolplatt' },
]
@ -62,7 +64,7 @@ const Footer = (): JSX.Element => {
<div className="p-5 bg-white dark:bg-gray-800 shadow-md rounded-md">
<div className="mb-3 text-gray-800 dark:text-gray-200">
@iteam1337 Digitalisering riktigt.
@iteam1337 We move fast and fix things.
</div>
<div>
<Link.External href="https://iteam.se" target="_blank">

View File

@ -3,7 +3,7 @@ import DownloadButtons from './DownloadButtons'
import Icon from './Icon'
import SectionTitle from './SectionTitle'
const price = 0
const price = 12
const baseFeatures = [
{
@ -33,17 +33,17 @@ const Pricing = (): JSX.Element => {
<section className="px-5 py-8 md:px-0 md:py-32" id="vad-kostar-det">
<div className="max-w-2xl mx-auto">
<SectionTitle
title="Hur kan det vara gratis?"
title="Varför inte gratis?"
text={`
Vi som bygger appen vill gärna fortsätta vidareutveckla den och även ha möjlighet att ge ersättning
till de som hjälper till. Vi har dock bestämt oss för att, försök, låta denna ersättning komma
från frivilliga donationer via Patreon.
till de som hjälper till. Vi gjorde ett försök att ge ut appen gratis och hoppades att fler kunde stötta oss via
Patreon istället. Det visade sig inte vara hållbart men om vi får fler sponsorer kommer vi göra appen gratis igen!
`}
/>
</div>
<div className="flex">
<div className="flex flex-col items-center inline-block px-5 py-8 mx-auto text-center shadow-lg rounded-md dark:bg-gray-800">
<h3 className="text-3xl text-gray-800 dark:text-gray-400">Tillfälligt</h3>
<h3 className="text-3xl text-gray-800 dark:text-gray-400">Just nu</h3>
<div className="mt-5 text-6xl text-pink-500">
{formatPrice(price)}
</div>

View File

@ -1,6 +1,6 @@
const Privacy = (): JSX.Element => {
return (
<div className="header">
<div>
<div className="max-w-6xl mx-auto px-5 md:px-0 my-5 md:my-24 prose dark:prose-dark">
<h1>Öppna Skolplattformen</h1>
<h2>Integritetspolicy</h2>

View File

@ -975,13 +975,6 @@
"resolved" "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz"
"version" "2.0.5"
"abort-controller@^3.0.0":
"integrity" "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="
"resolved" "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz"
"version" "3.0.0"
dependencies:
"event-target-shim" "^5.0.0"
"acorn-globals@^6.0.0":
"integrity" "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg=="
"resolved" "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz"
@ -1014,13 +1007,6 @@
"resolved" "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
"version" "7.4.1"
"agent-base@6":
"integrity" "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="
"resolved" "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
"version" "6.0.2"
dependencies:
"debug" "4"
"ajv-keywords@^3.5.2":
"integrity" "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
"resolved" "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz"
@ -1182,11 +1168,6 @@
"es-abstract" "^1.18.0-next.1"
"function-bind" "^1.1.1"
"arrify@^2.0.0":
"integrity" "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
"resolved" "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz"
"version" "2.0.1"
"asn1.js@^5.2.0":
"integrity" "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA=="
"resolved" "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz"
@ -1284,13 +1265,6 @@
"resolved" "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz"
"version" "1.11.0"
"axios@^0.21.1":
"integrity" "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA=="
"resolved" "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz"
"version" "0.21.1"
dependencies:
"follow-redirects" "^1.10.0"
"babel-eslint@10.1.0":
"integrity" "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg=="
"resolved" "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz"
@ -1387,7 +1361,7 @@
"mixin-deep" "^1.2.0"
"pascalcase" "^0.1.1"
"base64-js@^1.0.2", "base64-js@^1.3.0":
"base64-js@^1.0.2":
"integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
"resolved" "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
"version" "1.5.1"
@ -1404,11 +1378,6 @@
"resolved" "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz"
"version" "5.2.2"
"bignumber.js@^9.0.0":
"integrity" "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA=="
"resolved" "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz"
"version" "9.0.1"
"binary-extensions@^2.0.0":
"integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
"resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
@ -1558,11 +1527,6 @@
dependencies:
"node-int64" "^0.4.0"
"buffer-equal-constant-time@1.0.1":
"integrity" "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
"resolved" "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"
"version" "1.0.1"
"buffer-from@^1.0.0":
"integrity" "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
"resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz"
@ -2083,7 +2047,7 @@
dependencies:
"ms" "2.0.0"
"debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.1", "debug@4":
"debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.1":
"integrity" "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ=="
"resolved" "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
"version" "4.3.1"
@ -2292,13 +2256,6 @@
"jsbn" "~0.1.0"
"safer-buffer" "^2.1.0"
"ecdsa-sig-formatter@^1.0.11", "ecdsa-sig-formatter@1.0.11":
"integrity" "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="
"resolved" "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz"
"version" "1.0.11"
dependencies:
"safe-buffer" "^5.0.1"
"electron-to-chromium@^1.3.723":
"integrity" "sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A=="
"resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz"
@ -2591,11 +2548,6 @@
"resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
"version" "1.8.1"
"event-target-shim@^5.0.0":
"integrity" "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
"resolved" "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz"
"version" "5.0.1"
"events@^3.0.0":
"integrity" "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg=="
"resolved" "https://registry.npmjs.org/events/-/events-3.2.0.tgz"
@ -2700,7 +2652,7 @@
"assign-symbols" "^1.0.0"
"is-extendable" "^1.0.1"
"extend@^3.0.2", "extend@~3.0.2":
"extend@~3.0.2":
"integrity" "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
"resolved" "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz"
"version" "3.0.2"
@ -2761,11 +2713,6 @@
"resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
"version" "2.0.6"
"fast-text-encoding@^1.0.0":
"integrity" "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig=="
"resolved" "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz"
"version" "1.0.3"
"fastq@^1.6.0":
"integrity" "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g=="
"resolved" "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz"
@ -2842,11 +2789,6 @@
"resolved" "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz"
"version" "3.1.1"
"follow-redirects@^1.10.0":
"integrity" "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg=="
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz"
"version" "1.14.1"
"for-in@^1.0.2":
"integrity" "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
"resolved" "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz"
@ -2932,25 +2874,6 @@
"strip-ansi" "^3.0.1"
"wide-align" "^1.1.0"
"gaxios@^4.0.0":
"integrity" "sha512-pHplNbslpwCLMyII/lHPWFQbJWOX0B3R1hwBEOvzYi1GmdKZruuEHK4N9V6f7tf1EaPYyF80mui1+344p6SmLg=="
"resolved" "https://registry.npmjs.org/gaxios/-/gaxios-4.3.0.tgz"
"version" "4.3.0"
dependencies:
"abort-controller" "^3.0.0"
"extend" "^3.0.2"
"https-proxy-agent" "^5.0.0"
"is-stream" "^2.0.0"
"node-fetch" "^2.3.0"
"gcp-metadata@^4.2.0":
"integrity" "sha512-L9XQUpvKJCM76YRSmcxrR4mFPzPGsgZUH+GgHMxAET8qc6+BhRJq63RLhWakgEO2KKVgeSDVfyiNjkGSADwNTA=="
"resolved" "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.0.tgz"
"version" "4.3.0"
dependencies:
"gaxios" "^4.0.0"
"json-bigint" "^1.0.0"
"gensync@^1.0.0-beta.1":
"integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
"resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
@ -3076,37 +2999,6 @@
"merge2" "^1.3.0"
"slash" "^3.0.0"
"google-auth-library@^6.1.3":
"integrity" "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ=="
"resolved" "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz"
"version" "6.1.6"
dependencies:
"arrify" "^2.0.0"
"base64-js" "^1.3.0"
"ecdsa-sig-formatter" "^1.0.11"
"fast-text-encoding" "^1.0.0"
"gaxios" "^4.0.0"
"gcp-metadata" "^4.2.0"
"gtoken" "^5.0.4"
"jws" "^4.0.0"
"lru-cache" "^6.0.0"
"google-p12-pem@^3.0.3":
"integrity" "sha512-e9CwdD2QYkpvJsktki3Bm8P8FSGIneF+/42a9F9QHcQvJ73C2RoYZdrwRl6BhwksWtzl65gT4OnBROhUIFw95Q=="
"resolved" "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.1.tgz"
"version" "3.1.1"
dependencies:
"node-forge" "^0.10.0"
"google-spreadsheet@^3.1.15":
"integrity" "sha512-S5477f3Gf3Mz6AXgCw7dbaYnzu5aHou1AX4sDqrGboQWnAytkxqJGKQiXN+zzRTTcYzSTJCe0g7KqCPZO9xiOw=="
"resolved" "https://registry.npmjs.org/google-spreadsheet/-/google-spreadsheet-3.1.15.tgz"
"version" "3.1.15"
dependencies:
"axios" "^0.21.1"
"google-auth-library" "^6.1.3"
"lodash" "^4.17.20"
"graceful-fs@^4.1.2", "graceful-fs@^4.1.6", "graceful-fs@^4.2.0", "graceful-fs@^4.2.4":
"integrity" "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
"resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz"
@ -3117,15 +3009,6 @@
"resolved" "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz"
"version" "1.3.0"
"gtoken@^5.0.4":
"integrity" "sha512-mCcISYiaRZrJpfqOs0QWa6lfEM/C1V9ASkzFmuz43XBb5s1Vynh+CZy1ECeeJXVGx2PRByjYzb4Y4/zr1byr0w=="
"resolved" "https://registry.npmjs.org/gtoken/-/gtoken-5.3.0.tgz"
"version" "5.3.0"
dependencies:
"gaxios" "^4.0.0"
"google-p12-pem" "^3.0.3"
"jws" "^4.0.0"
"har-schema@^2.0.0":
"integrity" "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
"resolved" "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz"
@ -3292,14 +3175,6 @@
"resolved" "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz"
"version" "1.0.0"
"https-proxy-agent@^5.0.0":
"integrity" "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA=="
"resolved" "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz"
"version" "5.0.0"
dependencies:
"agent-base" "6"
"debug" "4"
"human-signals@^1.1.1":
"integrity" "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
"resolved" "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz"
@ -4233,13 +4108,6 @@
"resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
"version" "2.5.2"
"json-bigint@^1.0.0":
"integrity" "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="
"resolved" "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz"
"version" "1.0.0"
dependencies:
"bignumber.js" "^9.0.0"
"json-parse-even-better-errors@^2.3.0":
"integrity" "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
"resolved" "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
@ -4311,23 +4179,6 @@
"array-includes" "^3.1.2"
"object.assign" "^4.1.2"
"jwa@^2.0.0":
"integrity" "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA=="
"resolved" "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz"
"version" "2.0.0"
dependencies:
"buffer-equal-constant-time" "1.0.1"
"ecdsa-sig-formatter" "1.0.11"
"safe-buffer" "^5.0.1"
"jws@^4.0.0":
"integrity" "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="
"resolved" "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz"
"version" "4.0.0"
dependencies:
"jwa" "^2.0.0"
"safe-buffer" "^5.0.1"
"kind-of@^3.0.2", "kind-of@^3.0.3", "kind-of@^3.2.0":
"integrity" "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ="
"resolved" "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
@ -4777,16 +4628,11 @@
dependencies:
"lodash.toarray" "^4.4.0"
"node-fetch@^2.3.0", "node-fetch@2.6.1":
"node-fetch@2.6.1":
"integrity" "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
"resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz"
"version" "2.6.1"
"node-forge@^0.10.0":
"integrity" "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
"resolved" "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz"
"version" "0.10.0"
"node-html-parser@1.4.9":
"integrity" "sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw=="
"resolved" "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz"