feat: 🎸 Fix image load and typescript errors (#570)

* Update Cocoapods version
* Use new api GetRequestHeaders to get headers
* Remove warnings of missing colors and brushes
* Fix typing errors
* Change affected main branch to main
* Remove unused feature toggle
* Add dummy login checker to remove using any
This commit is contained in:
Andreas Eriksson 2021-12-02 15:34:15 +01:00 committed by GitHub
parent aea848f66a
commit 933a8840a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 84 additions and 54 deletions

View File

@ -1,4 +1,4 @@
import { CalendarItem } from '@skolplattformen/api-skolplattformen' import { CalendarItem } from '@skolplattformen/api'
import { useCalendar } from '@skolplattformen/hooks' import { useCalendar } from '@skolplattformen/hooks'
import { import {
Divider, Divider,

View File

@ -1,4 +1,4 @@
import { Child } from '@skolplattformen/api-skolplattformen' import { Child } from '@skolplattformen/api'
import React, { createContext, useContext } from 'react' import React, { createContext, useContext } from 'react'
interface ChildProviderProps { interface ChildProviderProps {

View File

@ -1,7 +1,7 @@
/* eslint-disable react-native-a11y/has-accessibility-hint */ /* eslint-disable react-native-a11y/has-accessibility-hint */
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack' import { StackNavigationProp } from '@react-navigation/stack'
import { Child } from '@skolplattformen/api-skolplattformen' import { Child } from '@skolplattformen/api'
import { import {
useCalendar, useCalendar,
useClassmates, useClassmates,

View File

@ -1,5 +1,5 @@
import { useNavigation } from '@react-navigation/core' import { useNavigation } from '@react-navigation/core'
import { Child } from '@skolplattformen/api-skolplattformen' import { Child } from '@skolplattformen/api'
import { useApi, useChildList } from '@skolplattformen/hooks' import { useApi, useChildList } from '@skolplattformen/hooks'
import { import {
Button, Button,

View File

@ -1,4 +1,4 @@
import { Classmate } from '@skolplattformen/api-skolplattformen' import { Classmate } from '@skolplattformen/api'
import { useClassmates } from '@skolplattformen/hooks' import { useClassmates } from '@skolplattformen/hooks'
import { import {
Divider, Divider,

View File

@ -1,5 +1,5 @@
/* eslint-disable react-native-a11y/has-accessibility-hint */ /* eslint-disable react-native-a11y/has-accessibility-hint */
import { Classmate } from '@skolplattformen/api-skolplattformen' import { Classmate } from '@skolplattformen/api'
import { import {
Button, Button,
MenuGroup, MenuGroup,

View File

@ -1,4 +1,4 @@
import { Child } from '@skolplattformen/api-skolplattformen' import { Child } from '@skolplattformen/api'
import { useTimetable } from '@skolplattformen/hooks' import { useTimetable } from '@skolplattformen/hooks'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components' import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import moment, { Moment } from 'moment' import moment, { Moment } from 'moment'

View File

@ -31,7 +31,7 @@ export const Image = ({
resizeMode = 'contain', resizeMode = 'contain',
}: ImageProps) => { }: ImageProps) => {
const { api } = useApi() const { api } = useApi()
const [headers, setHeaders] = useState() const [headers, setHeaders] = useState<{ [index: string]: string }>()
const { width: windowWidth } = useWindowDimensions() const { width: windowWidth } = useWindowDimensions()
const [dimensions, setDimensions] = useState({ width: 0, height: 0 }) const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
@ -40,7 +40,7 @@ export const Image = ({
const prefetchImageInformation = useCallback( const prefetchImageInformation = useCallback(
async (url: string) => { async (url: string) => {
if (!url) return if (!url) return
const { headers: newHeaders } = await api.getSession(url) const newHeaders = await api.getSessionHeaders(url)
console.log('[IMAGE] Getting image dimensions with headers', { console.log('[IMAGE] Getting image dimensions with headers', {
debugImageName, debugImageName,

View File

@ -1,4 +1,4 @@
import { MenuItem } from '@skolplattformen/api-skolplattformen' import { MenuItem } from '@skolplattformen/api'
import { useMenu } from '@skolplattformen/hooks' import { useMenu } from '@skolplattformen/hooks'
import { import {
Divider, Divider,

View File

@ -1,4 +1,4 @@
import { MenuItem } from '@skolplattformen/api-skolplattformen' import { MenuItem } from '@skolplattformen/api'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components' import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import React from 'react' import React from 'react'
import { View } from 'react-native' import { View } from 'react-native'

View File

@ -20,12 +20,12 @@ export const ModalWebView = ({
const [modalVisible, setModalVisible] = React.useState(true) const [modalVisible, setModalVisible] = React.useState(true)
const { api } = useApi() const { api } = useApi()
const [title, setTitle] = React.useState('...') const [title, setTitle] = React.useState('...')
const [headers, setHeaders] = useState() const [headers, setHeaders] = useState<{ [index: string]: string }>()
useEffect(() => { useEffect(() => {
const getHeaders = async (urlToGetSessionFor: string) => { const getHeaders = async (urlToGetSessionFor: string) => {
if (sharedCookiesEnabled) return if (sharedCookiesEnabled) return
const { headers: newHeaders } = await api.getSession(urlToGetSessionFor) const newHeaders = await api.getSessionHeaders(urlToGetSessionFor)
setHeaders(newHeaders) setHeaders(newHeaders)
} }

View File

@ -2,7 +2,7 @@ import { NavigationContainer } from '@react-navigation/native'
import { import {
Child as ChildType, Child as ChildType,
NewsItem as NewsItemType, NewsItem as NewsItemType,
} from '@skolplattformen/api-skolplattformen' } from '@skolplattformen/api'
import { useApi } from '@skolplattformen/hooks' import { useApi } from '@skolplattformen/hooks'
import { useTheme } from '@ui-kitten/components' import { useTheme } from '@ui-kitten/components'
import { Library } from 'libraries.json' import { Library } from 'libraries.json'

View File

@ -1,6 +1,6 @@
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack' import { StackNavigationProp } from '@react-navigation/stack'
import { NewsItem } from '@skolplattformen/api-skolplattformen' import { NewsItem } from '@skolplattformen/api'
import { StyleService, useStyleSheet } from '@ui-kitten/components' import { StyleService, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment' import moment from 'moment'
import React, { ReactNode } from 'react' import React, { ReactNode } from 'react'

View File

@ -1,4 +1,4 @@
import { Notification as NotificationType } from '@skolplattformen/api-skolplattformen' import { Notification as NotificationType } from '@skolplattformen/api'
import { StyleService, Text, useStyleSheet } from '@ui-kitten/components' import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment' import moment from 'moment'
import React from 'react' import React from 'react'

View File

@ -1,4 +1,4 @@
import { CalendarItem } from '@skolplattformen/api-skolplattformen' import { CalendarItem } from '@skolplattformen/api'
import { Button, MenuItem, OverflowMenu, Text } from '@ui-kitten/components' import { Button, MenuItem, OverflowMenu, Text } from '@ui-kitten/components'
import React from 'react' import React from 'react'
import RNCalendarEvents from 'react-native-calendar-events' import RNCalendarEvents from 'react-native-calendar-events'

View File

@ -1,8 +1,4 @@
import { import { Child, MenuItem, TimetableEntry } from '@skolplattformen/api'
Child,
MenuItem,
TimetableEntry,
} from '@skolplattformen/api-skolplattformen'
import { useMenu, useTimetable } from '@skolplattformen/hooks' import { useMenu, useTimetable } from '@skolplattformen/hooks'
import { import {
List, List,

View File

@ -2,8 +2,9 @@ import { Features, FeatureType } from '@skolplattformen/api'
import React from 'react' import React from 'react'
export const FeatureFlagsContext = React.createContext<Features>({ export const FeatureFlagsContext = React.createContext<Features>({
LOGIN_BANK_ID_SAME_DEVICE: false, LOGIN_BANK_ID_SAME_DEVICE_WITHOUT_ID: true,
FOOD_MENU: false, FOOD_MENU: false,
CLASS_LIST: true,
}) })
interface Props { interface Props {

View File

@ -16,7 +16,7 @@ export const SchoolPlatformProvider: React.FC = ({ children }) => {
'currentSchoolPlatform' 'currentSchoolPlatform'
) )
const changeSchoolPlatform = (platform: string) => { const changeSchoolPlatform = (platform) => {
setCurrentSchoolPlatform(platform) setCurrentSchoolPlatform(platform)
} }

View File

@ -10,13 +10,13 @@ export const schoolPlatforms = [
{ {
id: 'stockholm-skolplattformen', id: 'stockholm-skolplattformen',
displayName: 'Stockholm stad (Skolplattformen)', displayName: 'Stockholm stad (Skolplattformen)',
api: initSkolplattformen(fetch, CookieManager), api: initSkolplattformen(fetch as any, CookieManager),
features: featuresSkolPlattformen, features: featuresSkolPlattformen,
}, },
{ {
id: 'goteborg-hjarntorget', id: 'goteborg-hjarntorget',
displayName: 'Göteborg stad (Hjärntorget)', displayName: 'Göteborg stad (Hjärntorget)',
api: initHjarntorget(fetch, CookieManager), api: initHjarntorget(fetch as any, CookieManager),
features: featuresHjarntorget, features: featuresHjarntorget,
}, },
] ]

View File

@ -1,5 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage' import AsyncStorage from '@react-native-async-storage/async-storage'
import { User } from '@skolplattformen/api-skolplattformen' import { User } from '@skolplattformen/api'
import { act, renderHook } from '@testing-library/react-hooks' import { act, renderHook } from '@testing-library/react-hooks'
import usePersonalStorage from '../usePersonalStorage' import usePersonalStorage from '../usePersonalStorage'

View File

@ -669,4 +669,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 85f5a2dfa1de342b427eecb6e9652410ad153247 PODFILE CHECKSUM: 85f5a2dfa1de342b427eecb6e9652410ad153247
COCOAPODS: 1.10.1 COCOAPODS: 1.11.2

View File

@ -1,5 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage' import AsyncStorage from '@react-native-async-storage/async-storage'
import { User } from '@skolplattformen/api-skolplattformen' import { User } from '@skolplattformen/api'
import AppStorage from '../appStorage' import AppStorage from '../appStorage'
beforeEach(() => { beforeEach(() => {

View File

@ -1,5 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage' import AsyncStorage from '@react-native-async-storage/async-storage'
import { User } from '@skolplattformen/api-skolplattformen' import { User } from '@skolplattformen/api'
export default class AppStorage { export default class AppStorage {
static settingsStorageKeyPrefix = 'appsetting_' static settingsStorageKeyPrefix = 'appsetting_'

View File

@ -1,4 +1,4 @@
import { Guardian } from '@skolplattformen/api-skolplattformen' import { Guardian } from '@skolplattformen/api'
export const studentName = (name?: string) => name?.replace(/\s?\(\w+\)$/, '') export const studentName = (name?: string) => name?.replace(/\s?\(\w+\)$/, '')

View File

@ -1,4 +1,4 @@
import { NewsItem } from '@skolplattformen/api-skolplattformen' import { NewsItem } from '@skolplattformen/api'
import { useNews } from '@skolplattformen/hooks' import { useNews } from '@skolplattformen/hooks'
import { MatchData, Searcher } from 'fast-fuzzy' import { MatchData, Searcher } from 'fast-fuzzy'
import React, { ReactNode, useMemo } from 'react' import React, { ReactNode, useMemo } from 'react'

View File

@ -5,6 +5,7 @@ import { EvaIconsPack } from '@ui-kitten/eva-icons'
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { LanguageProvider } from '../context/language/languageContext' import { LanguageProvider } from '../context/language/languageContext'
import { translations } from './translation' import { translations } from './translation'
import { lightTheme } from '../design/themes'
export const render = ( export const render = (
ui: ReactElement<any, string>, ui: ReactElement<any, string>,
@ -14,7 +15,7 @@ export const render = (
return ( return (
<> <>
<IconRegistry icons={EvaIconsPack} /> <IconRegistry icons={EvaIconsPack} />
<ApplicationProvider {...eva} theme={eva.light}> <ApplicationProvider {...eva} theme={lightTheme}>
<LanguageProvider <LanguageProvider
cache={false} cache={false}
data={translations} data={translations}

View File

@ -5,6 +5,7 @@ import {
Classmate, Classmate,
CookieManager, CookieManager,
EtjanstChild, EtjanstChild,
Fetch,
Fetcher, Fetcher,
FetcherOptions, FetcherOptions,
LoginStatusChecker, LoginStatusChecker,
@ -24,7 +25,7 @@ import { decode } from 'he'
import { DateTime, FixedOffsetZone } from 'luxon' import { DateTime, FixedOffsetZone } from 'luxon'
import * as html from 'node-html-parser' import * as html from 'node-html-parser'
import { fakeFetcher } from './fake/fakeFetcher' import { fakeFetcher } from './fake/fakeFetcher'
import { checkStatus } from './loginStatus' import { checkStatus, DummyStatusChecker } from './loginStatus'
import { extractMvghostRequestBody, parseCalendarItem } from './parse/parsers' import { extractMvghostRequestBody, parseCalendarItem } from './parse/parsers'
import { import {
beginBankIdUrl, beginBankIdUrl,
@ -84,7 +85,7 @@ export class ApiHjarntorget extends EventEmitter implements Api {
} }
constructor( constructor(
fetch: typeof global.fetch, fetch: Fetch,
cookieManager: CookieManager, cookieManager: CookieManager,
options?: FetcherOptions options?: FetcherOptions
) { ) {
@ -138,6 +139,13 @@ export class ApiHjarntorget extends EventEmitter implements Api {
return this.personalNumber return this.personalNumber
} }
public async getSessionHeaders(url: string): Promise<{ [index: string]: string }> {
const cookie = await this.cookieManager.getCookieString(url)
return {
cookie,
}
}
async setSessionCookie(sessionCookie: string): Promise<void> { async setSessionCookie(sessionCookie: string): Promise<void> {
await this.fetch('login-cookie', hjarntorgetUrl, { await this.fetch('login-cookie', hjarntorgetUrl, {
headers: { headers: {
@ -490,13 +498,13 @@ export class ApiHjarntorget extends EventEmitter implements Api {
if((beginLoginRedirectResponse as any).url.endsWith("startPage.do")) { if((beginLoginRedirectResponse as any).url.endsWith("startPage.do")) {
// already logged in! // already logged in!
const emitter = new EventEmitter() const emitter = new DummyStatusChecker()
setTimeout(() => { setTimeout(() => {
this.isLoggedIn = true this.isLoggedIn = true
emitter.emit('OK') emitter.emit('OK')
this.emit('login') this.emit('login')
}, 50) }, 50)
return emitter; return emitter as LoginStatusChecker;
} }
console.log('prepping??? shibboleth') console.log('prepping??? shibboleth')

File diff suppressed because one or more lines are too long

View File

@ -28,10 +28,9 @@ const fetchMappings: { [name:string]: () => Response} = {
'event-role-members-24-821': eventRoleMembers24, 'event-role-members-24-821': eventRoleMembers24,
'calendars': calendars, 'calendars': calendars,
'calendar-14241345': calendar_14241345, 'calendar-14241345': calendar_14241345,
} }
export const fakeFetcher: Fetcher = (name: string, url: string, init?: any): Promise<Response> => { export const fakeFetcher: Fetcher = (name: string, url: string, init?: any): Promise<Response> => {
const responder = fetchMappings[name] ?? (() => {throw new Error("Request not faked for name: " + name)}) const responder = fetchMappings[name] ?? (() => {throw new Error("Request not faked for name: " + name)})
return Promise.resolve(responder()); return Promise.resolve(responder());
} }

View File

@ -10,7 +10,7 @@ import {
pollStatusUrl, pollStatusUrl,
} from './routes' } from './routes'
export class HjarntorgetChecker extends EventEmitter { export class HjarntorgetChecker extends EventEmitter implements LoginStatusChecker {
private fetcher: Fetcher private fetcher: Fetcher
private basePollingUrl: string private basePollingUrl: string
@ -120,3 +120,10 @@ export const checkStatus = (
fetch: Fetcher, fetch: Fetcher,
basePollingUrl: string basePollingUrl: string
): LoginStatusChecker => new HjarntorgetChecker(fetch, basePollingUrl) ): LoginStatusChecker => new HjarntorgetChecker(fetch, basePollingUrl)
export class DummyStatusChecker extends EventEmitter implements LoginStatusChecker {
token = ""
async cancel(): Promise<void> {
// do nothing
}
}

View File

@ -16,7 +16,7 @@ the concrete implementation of fetch and cookie handler must be injected.
#### react-native #### react-native
```javascript ```javascript
import init from '@skolplattformen/api-skolplattformen' import init from '@skolplattformen/api'
import CookieManager from '@react-native-cookies/cookies' import CookieManager from '@react-native-cookies/cookies'
const api = init(fetch, () => CookieManager.clearAll()) const api = init(fetch, () => CookieManager.clearAll())
@ -25,7 +25,7 @@ const api = init(fetch, () => CookieManager.clearAll())
#### node #### node
```javascript ```javascript
import init from '@skolplattformen/api-skolplattformen' import init from '@skolplattformen/api'
import nodeFetch from 'node-fetch' import nodeFetch from 'node-fetch'
import fetchCookie from 'fetch-cookie/node-fetch' import fetchCookie from 'fetch-cookie/node-fetch'
import { CookieJar } from 'tough-cookie' import { CookieJar } from 'tough-cookie'

View File

@ -28,7 +28,7 @@ import { decode } from 'he'
import { DateTime } from 'luxon' import { DateTime } from 'luxon'
import * as html from 'node-html-parser' import * as html from 'node-html-parser'
import * as fake from './fakeData' import * as fake from './fakeData'
import { checkStatus } from './loginStatusChecker' import { checkStatus, DummyStatusChecker } from './loginStatusChecker'
import * as parse from './parse/index' import * as parse from './parse/index'
import * as routes from './routes' import * as routes from './routes'
@ -94,6 +94,16 @@ export class ApiSkolplattformen extends EventEmitter implements Api {
} }
} }
public async getSessionHeaders(url: string): Promise<{ [index: string]: string }> {
const init = this.getRequestInit()
const cookie = await this.cookieManager.getCookieString(url)
return {
...init.headers,
cookie,
}
}
public async getSession( public async getSession(
url: string, url: string,
options?: RequestInit options?: RequestInit
@ -203,8 +213,7 @@ export class ApiSkolplattformen extends EventEmitter implements Api {
this.emit('login') this.emit('login')
}, 50) }, 50)
// eslint-disable-next-line @typescript-eslint/no-explicit-any const emitter = new DummyStatusChecker()
const emitter: any = new EventEmitter()
emitter.token = 'fake' emitter.token = 'fake'
return emitter return emitter
} }

View File

@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
import { loginStatus } from './routes'; import { loginStatus } from './routes';
import { AuthTicket, Fetcher, LoginStatusChecker } from '@skolplattformen/api'; import { AuthTicket, Fetcher, LoginStatusChecker } from '@skolplattformen/api';
export class Checker extends EventEmitter { export class Checker extends EventEmitter implements LoginStatusChecker {
public token: string; public token: string;
private fetcher: Fetcher; private fetcher: Fetcher;
@ -41,3 +41,10 @@ export const checkStatus = (
fetch: Fetcher, fetch: Fetcher,
ticket: AuthTicket ticket: AuthTicket
): LoginStatusChecker => new Checker(fetch, ticket) ): LoginStatusChecker => new Checker(fetch, ticket)
export class DummyStatusChecker extends EventEmitter implements LoginStatusChecker {
token = ""
async cancel(): Promise<void> {
// do nothing
}
}

View File

@ -21,6 +21,7 @@ export interface Api extends EventEmitter {
getPersonalNumber(): string | undefined getPersonalNumber(): string | undefined
login(personalNumber?: string): Promise<LoginStatusChecker> login(personalNumber?: string): Promise<LoginStatusChecker>
setSessionCookie(sessionCookie: string): Promise<void> setSessionCookie(sessionCookie: string): Promise<void>
getSessionHeaders(url: string): Promise<{ [index: string]: string }>
getUser(): Promise<User> getUser(): Promise<User>
getChildren(): Promise<EtjanstChild[]> getChildren(): Promise<EtjanstChild[]>
getCalendar(child: EtjanstChild): Promise<CalendarItem[]> getCalendar(child: EtjanstChild): Promise<CalendarItem[]>

View File

@ -18,7 +18,7 @@ In order to use api hooks, you must wrap your app in an ApiProvider
```javascript ```javascript
import React from 'react' import React from 'react'
import { ApiProvider } from '@skolplattformen/hooks' import { ApiProvider } from '@skolplattformen/hooks'
import init from '@skolplattformen/api-skolplattformen' import init from '@skolplattformen/api-skolplattformet'
import { CookieManager } from '@react-native-cookies/cookies' import { CookieManager } from '@react-native-cookies/cookies'
import AsyncStorage from '@react-native-async-storage/async-storage' import AsyncStorage from '@react-native-async-storage/async-storage'
import { RootComponent } from './components/root' import { RootComponent } from './components/root'

View File

@ -107,7 +107,7 @@ const hook = <T>(
if (newState.error) { if (newState.error) {
const description = `Error getting ${entityName} from API` const description = `Error getting ${entityName} from API`
reporter.error(newState.error, description) reporter.error && reporter.error(newState.error, description)
} }
} }
} }