chore(site): enable strict typescript and fix issues (#327)
This commit is contained in:
parent
8df0eb76f2
commit
70999a990e
|
@ -10,6 +10,8 @@
|
|||
}
|
||||
},
|
||||
"rules": {
|
||||
// No typing in project
|
||||
"react/prop-types": "off",
|
||||
// React included automatically in Next.js
|
||||
"react/react-in-jsx-scope": "off",
|
||||
// Allow unescaped characters like '
|
||||
|
|
|
@ -8,7 +8,7 @@ import screenshotLogin from '../assets/img/screenshots/screenshot_login.png'
|
|||
import SectionTitle from './SectionTitle'
|
||||
import Image from 'next/image'
|
||||
|
||||
const AppShots = () => {
|
||||
const AppShots = (): JSX.Element => {
|
||||
return (
|
||||
<section
|
||||
className="max-w-6xl px-5 py-8 mx-auto md:px-0 md:py-32"
|
||||
|
|
|
@ -15,7 +15,7 @@ import { H1 } from './Typography'
|
|||
import { useIntl } from 'react-intl'
|
||||
import { ButtonLinkPatreon } from './ButtonLink'
|
||||
|
||||
const Banner = () => {
|
||||
const Banner = (): JSX.Element => {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import Link from 'next/link'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
interface ButtonLinkProps {
|
||||
children: ReactNode
|
||||
href: string
|
||||
target?: string
|
||||
}
|
||||
type ButtonLinkProps = Pick<HTMLAnchorElement, 'href' | 'target'>
|
||||
|
||||
const ButtonLink = ({ children, href, target }: ButtonLinkProps) => {
|
||||
const ButtonLink: React.FC<ButtonLinkProps> = ({ children, href, target }) => {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
|
@ -20,15 +15,12 @@ const ButtonLink = ({ children, href, target }: ButtonLinkProps) => {
|
|||
)
|
||||
}
|
||||
|
||||
interface ButtonLinkInternalProps {
|
||||
children: ReactNode
|
||||
href: string
|
||||
}
|
||||
type ButtonLinkInternalProps = Pick<HTMLAnchorElement, 'href'>
|
||||
|
||||
export const ButtonLinkInternal = ({
|
||||
export const ButtonLinkInternal: React.FC<ButtonLinkInternalProps> = ({
|
||||
children,
|
||||
href,
|
||||
}: ButtonLinkInternalProps) => {
|
||||
}) => {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a className="inline-block px-4 py-2 font-bold text-indigo-800 border-2 border-indigo-800 rounded-full cursor-pointer md:px-8 md:py-4 hover:bg-indigo-800 hover:text-white">
|
||||
|
@ -38,15 +30,11 @@ export const ButtonLinkInternal = ({
|
|||
)
|
||||
}
|
||||
|
||||
interface ButtonLinkPatreonProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export const ButtonLinkPatreon = ({ children }: ButtonLinkPatreonProps) => {
|
||||
export const ButtonLinkPatreon: React.FC = ({ children }) => {
|
||||
return (
|
||||
<a
|
||||
href="https://www.patreon.com/oppnaskolplattformen"
|
||||
className="inline-block py-2 px-4 md:px-8 md:py-4 font-bold text-white border-2 bg-red-500 rounded-full hover:bg-white hover:border-red-500 hover:text-red-500"
|
||||
className="inline-block px-4 py-2 font-bold text-white bg-red-500 border-2 rounded-full md:px-8 md:py-4 hover:bg-white hover:border-red-500 hover:text-red-500"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
|
|
@ -4,7 +4,7 @@ import DownloadButtons from './DownloadButtons'
|
|||
import Section from './Section'
|
||||
import { H2 } from './Typography'
|
||||
|
||||
const CtaThree = () => {
|
||||
const CtaThree = (): JSX.Element => {
|
||||
return (
|
||||
<Section bg="bg-white">
|
||||
<div>
|
||||
|
|
|
@ -4,7 +4,7 @@ import DownloadButtons from './DownloadButtons'
|
|||
import Section from './Section'
|
||||
import { H2 } from './Typography'
|
||||
|
||||
const CtaTwo = () => {
|
||||
const CtaTwo = (): JSX.Element => {
|
||||
return (
|
||||
<Section>
|
||||
<Image src={img1} width="668" height="500" alt="" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ButtonLink, { ButtonLinkPatreon } from './ButtonLink'
|
||||
|
||||
const DownloadButtons = () => {
|
||||
const DownloadButtons = (): JSX.Element => {
|
||||
return (
|
||||
<div className="space-x-4">
|
||||
<ButtonLink
|
||||
|
@ -16,9 +16,7 @@ const DownloadButtons = () => {
|
|||
>
|
||||
Play Store
|
||||
</ButtonLink>
|
||||
<ButtonLinkPatreon>
|
||||
Stöd oss på Patreon!
|
||||
</ButtonLinkPatreon>
|
||||
<ButtonLinkPatreon>Stöd oss på Patreon!</ButtonLinkPatreon>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
import classnames from 'classnames'
|
||||
|
||||
const FeatureCard = ({ image, title, text, isActive }) => {
|
||||
interface FeatureCardProps {
|
||||
image: string
|
||||
title: string
|
||||
text: string
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
const FeatureCard = ({
|
||||
image,
|
||||
title,
|
||||
text,
|
||||
isActive,
|
||||
}: FeatureCardProps): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
|
|
|
@ -41,7 +41,7 @@ const FEATURES_DATA = [
|
|||
},
|
||||
]
|
||||
|
||||
const Features = () => {
|
||||
const Features = (): JSX.Element => {
|
||||
const swiperParams: SwiperOptions = {
|
||||
slidesPerView: 3,
|
||||
slidesPerGroup: 3,
|
||||
|
@ -83,7 +83,7 @@ const Features = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<section className="max-w-6xl mx-auto px-5 md:px-0" id="funktioner">
|
||||
<section className="max-w-6xl px-5 mx-auto md:px-0" id="funktioner">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<SectionTitle
|
||||
title="Enkelhet och snabbhet"
|
||||
|
@ -91,14 +91,14 @@ const Features = () => {
|
|||
/>
|
||||
</div>
|
||||
<Swiper className="feature-carousel" {...swiperParams}>
|
||||
{FEATURES_DATA.map((feature) => (
|
||||
<SwiperSlide key={feature.title}>
|
||||
{({ isActive }) => (
|
||||
{FEATURES_DATA.map(({ title, text, image }) => (
|
||||
<SwiperSlide key={title}>
|
||||
{({ isActive }: { isActive: boolean }) => (
|
||||
<FeatureCard
|
||||
isActive={isActive}
|
||||
title={feature.title}
|
||||
text={feature.text}
|
||||
image={feature.image}
|
||||
title={title}
|
||||
text={text}
|
||||
image={image}
|
||||
/>
|
||||
)}
|
||||
</SwiperSlide>
|
||||
|
|
|
@ -10,7 +10,7 @@ const team = [
|
|||
{ name: 'Öppna skolplattformen', twitter: 'oppnaskolplatt' },
|
||||
]
|
||||
|
||||
const Footer = () => {
|
||||
const Footer = (): JSX.Element => {
|
||||
return (
|
||||
<footer>
|
||||
<div className="items-start max-w-6xl px-5 py-8 mx-auto lg:py-12 grid lg:px-4 grid-cols-1 lg:grid-cols-4 gap-x-12 gap-y-5">
|
||||
|
|
|
@ -21,7 +21,7 @@ const FUNFACTS_DATA = [
|
|||
},
|
||||
]
|
||||
|
||||
const FunFacts = () => {
|
||||
const FunFacts = (): JSX.Element => {
|
||||
const [counter, setCounter] = React.useState({
|
||||
startCounter: false,
|
||||
})
|
||||
|
@ -37,7 +37,7 @@ const FunFacts = () => {
|
|||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-y-5">
|
||||
{FUNFACTS_DATA.map((funfact) => (
|
||||
<div className="text-center" key={funfact.title}>
|
||||
<span className="text-4xl sm:text-5xl text-indigo-500 whitespace-nowrap">
|
||||
<span className="text-4xl text-indigo-500 sm:text-5xl whitespace-nowrap">
|
||||
<VisibilitySensor
|
||||
onChange={onVisibilityChange}
|
||||
offset={{ top: 10 }}
|
||||
|
|
|
@ -28,7 +28,7 @@ const useMobile = (cb: UseMobileCallback) => {
|
|||
}, [])
|
||||
}
|
||||
|
||||
const HeaderHome = () => {
|
||||
const HeaderHome = (): JSX.Element => {
|
||||
const [displayMobileMenu, setDisplayMobileMenu] = React.useState(false)
|
||||
|
||||
useMobile((e) => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const Check = () => {
|
||||
export const Check = (): JSX.Element => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -14,7 +14,7 @@ export const Check = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export const Times = () => {
|
||||
export const Times = (): JSX.Element => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -30,7 +30,7 @@ export const Times = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export const Twitter = () => {
|
||||
export const Twitter = (): JSX.Element => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -42,7 +42,7 @@ export const Twitter = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export const Menu = () => {
|
||||
export const Menu = (): JSX.Element => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import Head from 'next/head'
|
||||
import { ReactNode } from 'react'
|
||||
import favImg from '../assets/img/favicon.png'
|
||||
import logo from '../assets/img/logo.png'
|
||||
import { GA_TRACKING_ID } from './gtag'
|
||||
|
||||
interface LayoutProps {
|
||||
children: ReactNode
|
||||
pageTitle: string
|
||||
}
|
||||
|
||||
const Layout = ({ children, pageTitle }: LayoutProps) => {
|
||||
const Layout: React.FC<LayoutProps> = ({
|
||||
children,
|
||||
pageTitle,
|
||||
}): JSX.Element => {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import Link from 'next/link'
|
||||
import classnames from 'classnames'
|
||||
import { ReactNode } from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
interface LinkInternalProps {
|
||||
children: ReactNode
|
||||
href: string
|
||||
}
|
||||
|
||||
const Internal = ({ href, children }: LinkInternalProps): JSX.Element => {
|
||||
const Internal: React.FC<LinkInternalProps> = ({
|
||||
href,
|
||||
children,
|
||||
}): JSX.Element => {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a className="text-indigo-800">{children}</a>
|
||||
|
@ -16,18 +17,17 @@ const Internal = ({ href, children }: LinkInternalProps): JSX.Element => {
|
|||
}
|
||||
|
||||
interface LinkExternalProps {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
href: string
|
||||
target?: string
|
||||
}
|
||||
|
||||
const External = ({
|
||||
const External: React.FC<LinkExternalProps> = ({
|
||||
className,
|
||||
href,
|
||||
children,
|
||||
target = '_blank',
|
||||
}: LinkExternalProps): JSX.Element => {
|
||||
}): JSX.Element => {
|
||||
return (
|
||||
<a
|
||||
className={classnames('text-indigo-800', className)}
|
||||
|
|
|
@ -8,7 +8,12 @@ interface NavLinksProps {
|
|||
onClick?: () => void
|
||||
}
|
||||
|
||||
const NavLinks = ({ onClick }: NavLinksProps) => {
|
||||
interface LinkProps {
|
||||
href: string
|
||||
to: string
|
||||
}
|
||||
|
||||
const NavLinks = ({ onClick }: NavLinksProps): JSX.Element => {
|
||||
const { pathname } = useRouter()
|
||||
const intl = useIntl()
|
||||
|
||||
|
@ -18,7 +23,7 @@ const NavLinks = ({ onClick }: NavLinksProps) => {
|
|||
return href.substring(0, hashIndex)
|
||||
}
|
||||
|
||||
const Link = ({ href, to, children }) =>
|
||||
const Link: React.FC<LinkProps> = ({ href, to, children }) =>
|
||||
path(href) === pathname ? (
|
||||
<ScrollLink
|
||||
activeClass="current"
|
||||
|
|
|
@ -32,7 +32,7 @@ const baseFeatures = [
|
|||
},
|
||||
]
|
||||
|
||||
const Pricing = () => {
|
||||
const Pricing = (): JSX.Element => {
|
||||
return (
|
||||
<section className="px-5 py-8 md:px-0 md:py-32" id="vad-kostar-det">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
|
|
|
@ -28,7 +28,7 @@ const baseFeatures = [
|
|||
},
|
||||
]
|
||||
|
||||
const Pricing = () => {
|
||||
const Pricing = (): JSX.Element => {
|
||||
return (
|
||||
<section className="px-5 py-8 md:px-0 md:py-32" id="vad-kostar-det">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const Privacy = () => {
|
||||
const Privacy = (): JSX.Element => {
|
||||
return (
|
||||
<div className="header">
|
||||
<div className="max-w-6xl mx-auto px-5 md:px-0 my-5 md:my-24 prose">
|
||||
|
|
|
@ -1,49 +1,52 @@
|
|||
const QA = () => {
|
||||
const QA = (): JSX.Element => {
|
||||
return (
|
||||
<div className="header">
|
||||
<div className="max-w-6xl px-5 mx-auto my-5 md:my-24 md:px-0 prose">
|
||||
<h1>Frågor och svar om Öppna skolplattformen</h1>
|
||||
|
||||
<h2>Om Utbildningsförvaltningens juridiska utredning och polisanmälan</h2>
|
||||
<h2>
|
||||
Om Utbildningsförvaltningens juridiska utredning och polisanmälan
|
||||
</h2>
|
||||
<p>
|
||||
Den 15 april släppte Utbildningsförvaltningen sin juridiska utredning
|
||||
av Öppna skolplattformen och den 16 april ska de ha polisanmält oss.
|
||||
Vi är förvånade över att utbildningsdirektör Lena Holmdahl agerar så,
|
||||
men tycker samtidigt att det ska bli skönt att någon annan än Utbildningsförvaltningen
|
||||
granskar ärendet. Därmed kanske vi kan få stopp på några av de missförstånd
|
||||
som nu sprids av förvaltningen, som att vi skulle ha bett om tillgång
|
||||
till Skolplattformens API (vi bad om <u>dokumentation</u> av API:et,
|
||||
vilket är en helt annan sak. Det vill de inte lämna ut och det beslutet
|
||||
har vi överklagat till kammarrätten).
|
||||
Nedan kommenterar vi delar av Utbildningsförvaltningens eget fråga-svar-dokument.
|
||||
men tycker samtidigt att det ska bli skönt att någon annan än
|
||||
Utbildningsförvaltningen granskar ärendet. Därmed kanske vi kan få
|
||||
stopp på några av de missförstånd som nu sprids av förvaltningen, som
|
||||
att vi skulle ha bett om tillgång till Skolplattformens API (vi bad om{' '}
|
||||
<u>dokumentation</u> av API:et, vilket är en helt annan sak. Det vill
|
||||
de inte lämna ut och det beslutet har vi överklagat till
|
||||
kammarrätten). Nedan kommenterar vi delar av Utbildningsförvaltningens
|
||||
eget fråga-svar-dokument.
|
||||
</p>
|
||||
<h3>Vad handlar Stockholms stads utredning om?</h3>
|
||||
<h4>Utbildningsförvaltningens svar</h4>
|
||||
<p>
|
||||
Stockholms stad har gjort en utredning av juridiken kring “Öppna skolplattformens”
|
||||
betal-app, som utan stadens medgivande behandlar information från
|
||||
Stockholms stads skolplattform.
|
||||
Stockholms stad har gjort en utredning av juridiken kring “Öppna
|
||||
skolplattformens” betal-app, som utan stadens medgivande behandlar
|
||||
information från Stockholms stads skolplattform.
|
||||
</p>
|
||||
<h4>Vår kommentar</h4>
|
||||
<p>
|
||||
Detta är ett felaktigt påstående. Vår app Öppna skolplattformen använder
|
||||
ett av Stockholms stads tillgängliggjorda API:er. Appen kommer åt den
|
||||
information som antingen är allmänt tillgänglig eller som användaren
|
||||
efter stark autentisering (i detta fall BankID) själv begär från
|
||||
Stockholms stads skolplattform.
|
||||
Detta konstaterades redan i februari av de externa it-experter som
|
||||
Utbildningsförvaltningen själva anlitat för att inspektera vår (öppet tillgängliga) källkod.
|
||||
Detta är ett felaktigt påstående. Vår app Öppna skolplattformen
|
||||
använder ett av Stockholms stads tillgängliggjorda API:er. Appen
|
||||
kommer åt den information som antingen är allmänt tillgänglig eller
|
||||
som användaren efter stark autentisering (i detta fall BankID) själv
|
||||
begär från Stockholms stads skolplattform. Detta konstaterades redan i
|
||||
februari av de externa it-experter som Utbildningsförvaltningen själva
|
||||
anlitat för att inspektera vår (öppet tillgängliga) källkod.
|
||||
</p>
|
||||
<h2>Om appen Öppna skolplattformen</h2>
|
||||
<h3>Vad är Öppna skolplattformen?</h3>
|
||||
<p>
|
||||
En app som ger föräldrar snabbare och lättare tillgång till sin egen
|
||||
information på Stockholms stads skolplattform. Appen är
|
||||
som ett lager ovanpå den befintliga plattformen som gör att vi kan visa
|
||||
samma information, men snabbare och med mindre krångel. Vi har byggt
|
||||
den för föräldrar. Vi har inte byggt något som kan användas av lärare
|
||||
eller elever, helt enkelt för att vi har utgått från den information
|
||||
vi själva har tillgång till som föräldrar, och de behov vi har.
|
||||
information på Stockholms stads skolplattform. Appen är som ett lager
|
||||
ovanpå den befintliga plattformen som gör att vi kan visa samma
|
||||
information, men snabbare och med mindre krångel. Vi har byggt den för
|
||||
föräldrar. Vi har inte byggt något som kan användas av lärare eller
|
||||
elever, helt enkelt för att vi har utgått från den information vi
|
||||
själva har tillgång till som föräldrar, och de behov vi har.
|
||||
</p>
|
||||
<h3>Vem ligger bakom Öppna skolplattformen?</h3>
|
||||
<p>
|
||||
|
@ -51,9 +54,10 @@ const QA = () => {
|
|||
Christian Landgren och Johan Öbrink. Vi är utvecklare och föräldrar
|
||||
till barn i grundskolan, och helt hänvisade till Skolplattformen i sin
|
||||
nuvarande form. Vi har tillsammans mer än 75 års erfarenhet som
|
||||
konsulter av att hantera personuppgifter (det gör vi dock inte i
|
||||
Öppna skolplattformen! Vi ser aldrig er information, bara våra egna barns)
|
||||
och är alla tre flera år i rad utnämnda till Sveriges bästa utvecklare av IDG.
|
||||
konsulter av att hantera personuppgifter (det gör vi dock inte i Öppna
|
||||
skolplattformen! Vi ser aldrig er information, bara våra egna barns)
|
||||
och är alla tre flera år i rad utnämnda till Sveriges bästa utvecklare
|
||||
av IDG.
|
||||
</p>
|
||||
<h3>Varför har ni skapat Öppna skolplattformen?</h3>
|
||||
<p>
|
||||
|
@ -61,27 +65,32 @@ const QA = () => {
|
|||
informationen som finns i Skolplattformen men den är fruktansvärt
|
||||
otillgänglig. Fråga vilken förälder eller lärare som helst. Vi är
|
||||
utvecklare. Tekniken och kunskapen för att bygga ett bra verktyg
|
||||
finns. Till slut gick det inte att tyst betrakta hur kommunen
|
||||
bränner sådana oerhörda pengar på en så undermålig produkt, på grund
|
||||
av undermålig upphandling och okunnig kravställning.
|
||||
finns. Till slut gick det inte att tyst betrakta hur kommunen bränner
|
||||
sådana oerhörda pengar på en så undermålig produkt, på grund av
|
||||
undermålig upphandling och okunnig kravställning.
|
||||
</p>
|
||||
<h3>Vilken data har Öppna skolplattformen tillgång till?</h3>
|
||||
<p>
|
||||
Du som använder vår app har, när du identifierat dig gentemot Stockholms stad,
|
||||
tillgång till samma data som genom kommunens app eller webbsida.
|
||||
Vi bakom Öppna skolplattformen kan inte se någon annan information än våra egna barns.
|
||||
Den information du hämtar visas bara för dig och hanteras bara på din mobil eller surfplatta.
|
||||
Ingen information skickas från den mobila enheten eller lagras,
|
||||
analyseras eller processas någon annanstans. Inga tredjepartssystem
|
||||
har tillgång till någon del av informationen.
|
||||
Du som använder vår app har, när du identifierat dig gentemot
|
||||
Stockholms stad, tillgång till samma data som genom kommunens app
|
||||
eller webbsida. Vi bakom Öppna skolplattformen kan inte se någon annan
|
||||
information än våra egna barns. Den information du hämtar visas bara
|
||||
för dig och hanteras bara på din mobil eller surfplatta. Ingen
|
||||
information skickas från den mobila enheten eller lagras, analyseras
|
||||
eller processas någon annanstans. Inga tredjepartssystem har tillgång
|
||||
till någon del av informationen.
|
||||
</p>
|
||||
<h3>Är Öppna skolplattformen laglig?</h3>
|
||||
<p>Ja.</p>
|
||||
<h3>Hur säker är Öppna skolplattformen?</h3>
|
||||
<p>
|
||||
Din information är lika säker som i Skolplattformen. Vi är integritetsfanatiker och redogör
|
||||
för vår syn på dataskydd i Öppna skolplattformen i
|
||||
<a href="https://skolplattformen.org/integritet">vår integritetspolicy</a>.
|
||||
Din information är lika säker som i Skolplattformen. Vi är
|
||||
integritetsfanatiker och redogör för vår syn på dataskydd i Öppna
|
||||
skolplattformen i
|
||||
<a href="https://skolplattformen.org/integritet">
|
||||
vår integritetspolicy
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<h3>Men ni hanterar ju personinformation?</h3>
|
||||
<p>
|
||||
|
@ -90,27 +99,29 @@ const QA = () => {
|
|||
Varje förälder legitimerar sig med BankID.
|
||||
</p>
|
||||
<h3>
|
||||
Den kommunala Skolplattformen har kritiserats
|
||||
för att hantera t ex personinformation på ett osäkert sätt. Är detta
|
||||
något ni sett exempel på när ni gjort er utveckling? Några andra
|
||||
brister i den kommunala Skolplattformen ni upptäckt?
|
||||
Den kommunala Skolplattformen har kritiserats för att hantera t ex
|
||||
personinformation på ett osäkert sätt. Är detta något ni sett exempel
|
||||
på när ni gjort er utveckling? Några andra brister i den kommunala
|
||||
Skolplattformen ni upptäckt?
|
||||
</h3>
|
||||
<p>
|
||||
Ja, vi har upptäckt sårbarheter som inte borde finnas i ett sådant här system.
|
||||
De har vi rapporterat på ett ansvarsfullt sätt. Två fall har uppmärksammats
|
||||
i media. I ett av fallen har kommunen täppt till luckan.
|
||||
Vi kommer att fortsätta att rapportera eventuella sårbarheter vi upptäcker i vårt utvecklingsarbete.
|
||||
Ja, vi har upptäckt sårbarheter som inte borde finnas i ett sådant här
|
||||
system. De har vi rapporterat på ett ansvarsfullt sätt. Två fall har
|
||||
uppmärksammats i media. I ett av fallen har kommunen täppt till
|
||||
luckan. Vi kommer att fortsätta att rapportera eventuella sårbarheter
|
||||
vi upptäcker i vårt utvecklingsarbete.
|
||||
</p>
|
||||
<h3>
|
||||
Vilken information och funktionalitet finns idag tillgänglig i Öppna
|
||||
skolplattformen?
|
||||
</h3>
|
||||
<p>
|
||||
Vi har gjort det lättare att läsa veckobrev och matsedel, hitta notifieringar och frånvaroanmäla.
|
||||
Vi gör nya releaser hela tiden och har byggt appen som man bygger appar i
|
||||
dag, inte som man gjorde för sju år sedan. Vi har utgått från föräldrars önskemål
|
||||
– inte minst så att de som är förälder till flera barn lättare
|
||||
ska kunna få fullständig överblick av kommande prov, läxor och idrottsdagar.
|
||||
Vi har gjort det lättare att läsa veckobrev och matsedel, hitta
|
||||
notifieringar och frånvaroanmäla. Vi gör nya releaser hela tiden och
|
||||
har byggt appen som man bygger appar i dag, inte som man gjorde för
|
||||
sju år sedan. Vi har utgått från föräldrars önskemål – inte minst så
|
||||
att de som är förälder till flera barn lättare ska kunna få
|
||||
fullständig överblick av kommande prov, läxor och idrottsdagar.
|
||||
</p>
|
||||
<h3>
|
||||
Vilken information/funktionalitet kommer att finnas tillgänglig?
|
||||
|
@ -120,11 +131,10 @@ const QA = () => {
|
|||
veckobrev så att aktiviteter placeras ut på en kalender – dvs att en
|
||||
förälder till tre barn ska få en vy av vad som ska packas med till
|
||||
skolan under nästa vecka på en och samma plats. Vi vill få in flera
|
||||
språkalternativ för att öka tillgängligheten.
|
||||
Vi har massor av idéer till förbättringar som kommer dyka upp med
|
||||
tiden och vi jobbar med löpande releaser snarare än att vänta på
|
||||
att allt är klart. Med er hjälp kommer vi kunna prioritera de funktioner
|
||||
som hjälper mest.
|
||||
språkalternativ för att öka tillgängligheten. Vi har massor av idéer
|
||||
till förbättringar som kommer dyka upp med tiden och vi jobbar med
|
||||
löpande releaser snarare än att vänta på att allt är klart. Med er
|
||||
hjälp kommer vi kunna prioritera de funktioner som hjälper mest.
|
||||
</p>
|
||||
<h3>
|
||||
Jag är lärare eller annan typ av användare. Snälla bygg något åt mig!
|
||||
|
@ -147,12 +157,12 @@ const QA = () => {
|
|||
Förutom att hjälpa oss själva slippa Skolplattformens horribla
|
||||
användarupplevelse har vi försökt illustrera en alternativ väg framåt.
|
||||
Vi byggde litet och utgick helt och hållet från användarbehov (dvs
|
||||
vårt eget). All kod är släppt som öppen källkod så att den kan granskas
|
||||
av andra och ett större värde kan komma världen till godo. Så borde
|
||||
den offentliga sektorn alltid arbeta. Snarare än samordna, planera och
|
||||
krava: göra, utforska och dela med sig. Snarare än få, stora, rigida
|
||||
projekt: många, små, agila. Snarare än gårdagens misslyckade
|
||||
IT-satsningar: öppna API:er, öppen källkod och öppen data.
|
||||
vårt eget). All kod är släppt som öppen källkod så att den kan
|
||||
granskas av andra och ett större värde kan komma världen till godo. Så
|
||||
borde den offentliga sektorn alltid arbeta. Snarare än samordna,
|
||||
planera och krava: göra, utforska och dela med sig. Snarare än få,
|
||||
stora, rigida projekt: många, små, agila. Snarare än gårdagens
|
||||
misslyckade IT-satsningar: öppna API:er, öppen källkod och öppen data.
|
||||
</p>
|
||||
<h3>Vad är er syn på den kommunala Skolplattformen?</h3>
|
||||
<p>
|
||||
|
@ -166,11 +176,11 @@ const QA = () => {
|
|||
</p>
|
||||
<h3>Vad anser ni borde göras med Skolplattformen?</h3>
|
||||
<p>
|
||||
Skolplattformen är uppbyggd i flera delar. Dels
|
||||
innehåller den bakomliggande delar som hanterar informationen som
|
||||
lagras på ett säkert sätt och dels innehåller den en webbsida och app
|
||||
som hämtar informationen och presenterar den. Vad vi förstår har mest
|
||||
energi lagts på de bakomliggande delarna. Resultatet av det är att
|
||||
Skolplattformen är uppbyggd i flera delar. Dels innehåller den
|
||||
bakomliggande delar som hanterar informationen som lagras på ett
|
||||
säkert sätt och dels innehåller den en webbsida och app som hämtar
|
||||
informationen och presenterar den. Vad vi förstår har mest energi
|
||||
lagts på de bakomliggande delarna. Resultatet av det är att
|
||||
användarupplevelsen för många målgrupper har blivit lidande. Vi har
|
||||
visat att det med relativt små resurser går att börja om från början
|
||||
och bygga en ny s.k. frontend – dvs app och webbsida som återanvänder
|
||||
|
@ -198,31 +208,34 @@ const QA = () => {
|
|||
om det ni gjort?
|
||||
</h3>
|
||||
<p>
|
||||
Framför allt har vi anmält ett antal säkerhetsluckor i Stockholms stads it-system.
|
||||
En av dem har anmälts till IMY, den andra ännu inte.
|
||||
Eftersom den är allvarlig och vi inte är trygga med att Utbildningsförvaltningen
|
||||
utrett om information läckt på ett bra sätt kommer vi att insistera på att den anmäls.
|
||||
Utbildningsförvaltningen har också anmält vår app.
|
||||
Självklart kommer vi att redovisa IMY:s ställningstagande när det kommer.
|
||||
Framför allt har vi anmält ett antal säkerhetsluckor i Stockholms
|
||||
stads it-system. En av dem har anmälts till IMY, den andra ännu inte.
|
||||
Eftersom den är allvarlig och vi inte är trygga med att
|
||||
Utbildningsförvaltningen utrett om information läckt på ett bra sätt
|
||||
kommer vi att insistera på att den anmäls. Utbildningsförvaltningen
|
||||
har också anmält vår app. Självklart kommer vi att redovisa IMY:s
|
||||
ställningstagande när det kommer.
|
||||
</p>
|
||||
<h3>Hur har kommunen reagerat?</h3>
|
||||
<p>
|
||||
Inte som vi hade hoppats, trots flera möten där vi förklarat exakt vad
|
||||
appen gör rent tekniskt. Sammanfattningsvis kan man säga att de lagt mer
|
||||
energi på att misstänkliggöra oss än att täppa igen de stora säkerhetsluckor
|
||||
vi hittat i deras system. Det är minst sagt olyckligt.
|
||||
Du hittar alla våra svar på deras utredning i ett separat QA-segment ovan.
|
||||
appen gör rent tekniskt. Sammanfattningsvis kan man säga att de lagt
|
||||
mer energi på att misstänkliggöra oss än att täppa igen de stora
|
||||
säkerhetsluckor vi hittat i deras system. Det är minst sagt olyckligt.
|
||||
Du hittar alla våra svar på deras utredning i ett separat QA-segment
|
||||
ovan.
|
||||
</p>
|
||||
<h3>Varför reagerar de så, tror ni?</h3>
|
||||
<p>
|
||||
Det är svårt att spekulera i. Men deras tekniska förståelse är förbluffande låg.
|
||||
Det är svårt att spekulera i. Men deras tekniska förståelse är
|
||||
förbluffande låg.
|
||||
</p>
|
||||
<h3>Är ni oroliga för att bli stämda?</h3>
|
||||
<p>
|
||||
Utbildningsdirektör Lena Holmdahl har polisanmält oss.
|
||||
Det är förstås obehagligt och vi välkomnar inte slöseri med
|
||||
polisens utredningsresurser. Men samtidigt är det skönt att ärendet
|
||||
granskas av någon annan än Utbildningsförvaltningen.
|
||||
Utbildningsdirektör Lena Holmdahl har polisanmält oss. Det är förstås
|
||||
obehagligt och vi välkomnar inte slöseri med polisens
|
||||
utredningsresurser. Men samtidigt är det skönt att ärendet granskas av
|
||||
någon annan än Utbildningsförvaltningen.
|
||||
</p>
|
||||
<h3>Har ni rätt att använda varumärket Skolplattformen.</h3>
|
||||
<p>
|
||||
|
@ -235,15 +248,16 @@ const QA = () => {
|
|||
</h3>
|
||||
<p>
|
||||
Appen kostar 12 kronor. Intäkten registreras i handelsbolaget Not Free
|
||||
Beer som ägs av tre av utvecklarna och går till att täcka kostnader för inköp.
|
||||
Det täcker inte på långa vägar den tid vi lagt ner.
|
||||
Med en låg engångskostnad ökar vi chansen att vi orkar syssla med
|
||||
underhåll och uppdateringar. Vi vill ju ha en stabil lösning som
|
||||
håller. Just nu jobbar vi på egen fritid med något som förbättrar det
|
||||
kommunen lagt en miljard av allmänna medel på.
|
||||
Beer som ägs av tre av utvecklarna och går till att täcka kostnader
|
||||
för inköp. Det täcker inte på långa vägar den tid vi lagt ner. Med en
|
||||
låg engångskostnad ökar vi chansen att vi orkar syssla med underhåll
|
||||
och uppdateringar. Vi vill ju ha en stabil lösning som håller. Just nu
|
||||
jobbar vi på egen fritid med något som förbättrar det kommunen lagt en
|
||||
miljard av allmänna medel på.
|
||||
</p>
|
||||
<h3>
|
||||
Är det moraliskt att tjäna pengar på något som kommunen borde erbjuda gratis?
|
||||
Är det moraliskt att tjäna pengar på något som kommunen borde erbjuda
|
||||
gratis?
|
||||
</h3>
|
||||
<p>
|
||||
Det är bra att föräldrar har en helt frivillig möjlighet att snabbare
|
||||
|
@ -252,21 +266,28 @@ const QA = () => {
|
|||
fungerar så dåligt, både för oss föräldrar och för alla de lärare som
|
||||
är helt utlämnade åt den.
|
||||
</p>
|
||||
<h2>Om hur appen Öppna skolplattformen utvecklats och hur du kan bidra till utvecklingen</h2>
|
||||
<h2>
|
||||
Om hur appen Öppna skolplattformen utvecklats och hur du kan bidra
|
||||
till utvecklingen
|
||||
</h2>
|
||||
<h3>Hur rapporterar man buggar och önskemål?</h3>
|
||||
<p>
|
||||
Vi är enormt tacksamma för alla buggrapporter och förslag vi får och satsar mycket på att så
|
||||
snabbt som möjligt fixa de saker som dyker upp. För att få lite
|
||||
ordning så försöker vi samla alla buggar och önskemål på samma ställe, Github.
|
||||
Vi är enormt tacksamma för alla buggrapporter och förslag vi får och
|
||||
satsar mycket på att så snabbt som möjligt fixa de saker som dyker
|
||||
upp. För att få lite ordning så försöker vi samla alla buggar och
|
||||
önskemål på samma ställe, Github.
|
||||
<a href="https://github.com/kolplattformen/skolplattformen/issues">
|
||||
Klicka här</a> för att se vilka funktioner och buggar vi redan har tagit emot och jobbar på.
|
||||
Klicka här
|
||||
</a>{' '}
|
||||
för att se vilka funktioner och buggar vi redan har tagit emot och
|
||||
jobbar på.
|
||||
</p>
|
||||
<h3>Hur gick ni tillväga?</h3>
|
||||
<p>
|
||||
Allt bygger på reverse engineering. Vi öppnade DevTools i Chrome och
|
||||
loggade in. Sen antecknade vi alla url:er och payloads. Vi
|
||||
tog koden för att anropa API:et och byggde ett npm-paket av den så att
|
||||
appen kunde köra proxyn i en process på telefonen.
|
||||
loggade in. Sen antecknade vi alla url:er och payloads. Vi tog koden
|
||||
för att anropa API:et och byggde ett npm-paket av den så att appen
|
||||
kunde köra proxyn i en process på telefonen.
|
||||
</p>
|
||||
<h3>Vilka tekniska utmaningar har ni överkommit och hur?</h3>
|
||||
<p>
|
||||
|
@ -286,8 +307,8 @@ const QA = () => {
|
|||
Det är en anspelning på hur GNU-projektet beskriver fri programvara:
|
||||
To understand the concept, you should think of “free” as in “free
|
||||
speech,” not as in “free beer”. Då vi har valt att tillgängliggöra all
|
||||
kod som öppen källkod (Apache 2.0) men ändå ta betalt för appen, tyckte
|
||||
vi att namnet var passande.
|
||||
kod som öppen källkod (Apache 2.0) men ändå ta betalt för appen,
|
||||
tyckte vi att namnet var passande.
|
||||
</p>
|
||||
<h3>Kontakta oss</h3>
|
||||
<p>
|
||||
|
@ -295,7 +316,7 @@ const QA = () => {
|
|||
<a href="mailto:info@skolplattformen.org">dev@skolplattformen.org</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div >
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
import classnames from 'classnames'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
interface SectionProps {
|
||||
bg?: string
|
||||
children: ReactNode
|
||||
id?: string
|
||||
padding?: string
|
||||
}
|
||||
|
||||
const Section = ({
|
||||
const Section: React.FC<SectionProps> = ({
|
||||
bg = 'bg-gray-100',
|
||||
padding = 'py-8 md:py-20',
|
||||
children,
|
||||
id,
|
||||
}: SectionProps) => {
|
||||
}) => {
|
||||
return (
|
||||
<section className={classnames('grid grid-main', bg, padding)} id={id}>
|
||||
<div className="items-center grid gap-y-5 md:gap-y-20 col-start-3 col-end-4 grid-cols-1 lg:grid-cols-2">
|
||||
|
|
|
@ -3,7 +3,7 @@ interface SectionTitleProps {
|
|||
title: string
|
||||
}
|
||||
|
||||
const SectionTitle = ({ text, title }: SectionTitleProps) => {
|
||||
const SectionTitle = ({ text, title }: SectionTitleProps): JSX.Element => {
|
||||
return (
|
||||
<div className="mb-16 text-center space-y-5">
|
||||
<h2 className="text-4xl md:text-5xl font-bold leading-tight text-gray-800">
|
||||
|
|
|
@ -1,30 +1,39 @@
|
|||
const Status = () => {
|
||||
return (
|
||||
<div className="max-w-6xl px-5 mx-auto my-5 md:my-24 md:px-0 prose">
|
||||
<h1>Status</h1>
|
||||
<h3>Funkar appen som den ska?</h3>
|
||||
<p>
|
||||
Senast vi kollade!
|
||||
<br />
|
||||
✅ iPhone
|
||||
<br />
|
||||
✅ Android
|
||||
</p>
|
||||
<p>
|
||||
Vi har inga rapporter om att appen har problem för tillfället.
|
||||
Har du upptäckt problem nu? Hjälp oss fixa det!
|
||||
</p>
|
||||
<p>
|
||||
Det finns det tre sätt att göra det (i stigande ordning av braighet):
|
||||
<ul>
|
||||
<li>Skicka en tweet 🥉</li>
|
||||
<li><a href="https://github.com/kolplattformen/skolplattformen/issues">Lägg en buggrapport här</a> 🥈</li>
|
||||
<li><a href="https://github.com/kolplattformen/skolplattformen/pulls">Skicka en PR</a> 🥇</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Status
|
||||
|
||||
const Status = (): JSX.Element => {
|
||||
return (
|
||||
<div className="max-w-6xl px-5 mx-auto my-5 md:my-24 md:px-0 prose">
|
||||
<h1>Status</h1>
|
||||
<h3>Funkar appen som den ska?</h3>
|
||||
<p>
|
||||
Senast vi kollade!
|
||||
<br />
|
||||
✅ iPhone
|
||||
<br />✅ Android
|
||||
</p>
|
||||
<p>
|
||||
Vi har inga rapporter om att appen har problem för tillfället. Har du
|
||||
upptäckt problem nu? Hjälp oss fixa det!
|
||||
</p>
|
||||
<p>
|
||||
Det finns det tre sätt att göra det (i stigande ordning av braighet):
|
||||
<ul>
|
||||
<li>Skicka en tweet 🥉</li>
|
||||
<li>
|
||||
<a href="https://github.com/kolplattformen/skolplattformen/issues">
|
||||
Lägg en buggrapport här
|
||||
</a>{' '}
|
||||
🥈
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/kolplattformen/skolplattformen/pulls">
|
||||
Skicka en PR
|
||||
</a>{' '}
|
||||
🥇
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Status
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ export const testimonials = [
|
|||
},
|
||||
]
|
||||
|
||||
const Testimonials = () => {
|
||||
const Testimonials = (): JSX.Element => {
|
||||
return (
|
||||
<Section padding="py-8 md:pt-32 md:pb-20">
|
||||
{testimonials.map((testimonial) => (
|
||||
|
|
|
@ -16,7 +16,7 @@ interface TimelineProps {
|
|||
events: TimelineEvent[]
|
||||
}
|
||||
|
||||
const Timeline = ({ events }: TimelineProps) => {
|
||||
const Timeline = ({ events }: TimelineProps): JSX.Element => {
|
||||
return (
|
||||
<ul className="max-w-2xl border-gray-200 md:mx-auto md:border-l-2 space-y-4 md:space-y-12">
|
||||
{events.map(({ date, media, importantDates, overview }) => (
|
||||
|
@ -64,7 +64,7 @@ const Timeline = ({ events }: TimelineProps) => {
|
|||
</ul>
|
||||
</div>
|
||||
)}
|
||||
{media?.length > 0 && (
|
||||
{media.length > 0 && (
|
||||
<div className="mt-4 text-sm">
|
||||
<div className="font-bold">Media</div>
|
||||
<ul className="pl-5 mt-2 list-disc space-y-2">
|
||||
|
|
|
@ -2,7 +2,7 @@ import { events } from '../data/timelineEvents'
|
|||
import { ButtonLinkInternal } from './ButtonLink'
|
||||
import Timeline from './Timeline'
|
||||
|
||||
const TimelineLatest = () => {
|
||||
const TimelineLatest = (): JSX.Element => {
|
||||
const latestMonthsEvents = events.slice(0, 1)
|
||||
|
||||
return (
|
||||
|
@ -22,12 +22,14 @@ const TimelineLatest = () => {
|
|||
uppmärksamhet.
|
||||
</p>
|
||||
<p>
|
||||
Stockholms stads skolplattform har fått omfattande kritik för att
|
||||
den kostat enorma pengar, inte är användarvänlig och har stora
|
||||
säkerhetsbrister. Vår förväntan var att vårt initiativ skulle välkomnas och att vi skulle kunna samarbeta
|
||||
med staden för att skapa ännu bättre lösningar. Istället
|
||||
attackerar staden genom Utbildningsdirektör Lena Holmdahl appen och oss som privatpersoner, senast genom en polisanmälan.
|
||||
I ett försök att skapa transparens har vi sammanställt vad som hänt nedan.
|
||||
Stockholms stads skolplattform har fått omfattande kritik för att den
|
||||
kostat enorma pengar, inte är användarvänlig och har stora
|
||||
säkerhetsbrister. Vår förväntan var att vårt initiativ skulle
|
||||
välkomnas och att vi skulle kunna samarbeta med staden för att skapa
|
||||
ännu bättre lösningar. Istället attackerar staden genom
|
||||
Utbildningsdirektör Lena Holmdahl appen och oss som privatpersoner,
|
||||
senast genom en polisanmälan. I ett försök att skapa transparens har
|
||||
vi sammanställt vad som hänt nedan.
|
||||
</p>
|
||||
<ButtonLinkInternal href="/aktuellt">
|
||||
Läs hela historien
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import { ReactNode } from 'react'
|
||||
|
||||
interface H1Props {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export const H1 = ({ children }: H1Props) => {
|
||||
export const H1: React.FC = ({ children }) => {
|
||||
return (
|
||||
<h1 className="mb-5 text-4xl md:text-5xl font-semibold text-gray-800">
|
||||
{children}
|
||||
|
@ -12,11 +6,7 @@ export const H1 = ({ children }: H1Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
interface H2Props {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export const H2 = ({ children }: H2Props) => {
|
||||
export const H2: React.FC = ({ children }) => {
|
||||
return (
|
||||
<h2 className="mb-5 text-5xl font-semibold text-gray-800">{children}</h2>
|
||||
)
|
||||
|
|
|
@ -27,7 +27,7 @@ test('pages renders correctly and displays important dates and media', () => {
|
|||
|
||||
test('handles missing Intl', () => {
|
||||
const intl = global.Intl
|
||||
global.Intl = undefined
|
||||
global.Intl = (undefined as unknown) as typeof Intl
|
||||
|
||||
setup()
|
||||
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
export const GA_TRACKING_ID = 'G-KX6E6T6FXS'
|
||||
|
||||
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
|
||||
export const pageview = (url) => {
|
||||
export const pageview = (url: string): void => {
|
||||
window.gtag('config', GA_TRACKING_ID, {
|
||||
page_path: url.replace('#', ''),
|
||||
})
|
||||
}
|
||||
|
||||
interface GoogleEvent {
|
||||
action: string
|
||||
category: string
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
// https://developers.google.com/analytics/devguides/collection/gtagjs/events
|
||||
export const event = ({ action, category, label, value }) => {
|
||||
export const event = ({
|
||||
action,
|
||||
category,
|
||||
label,
|
||||
value,
|
||||
}: GoogleEvent): void => {
|
||||
window.gtag('event', action, {
|
||||
value,
|
||||
event_category: category,
|
||||
|
|
|
@ -18,7 +18,6 @@ const en = {
|
|||
through Patreon? We'll see... Until April 29:th, the app is free
|
||||
on both iOS and Android. After that we have to decide if it was a
|
||||
good idea or not. So tip yor friends! And please support us on Patreon ❤️`,
|
||||
}
|
||||
} as const
|
||||
|
||||
export default en
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import sv from './sv'
|
||||
import en from './en'
|
||||
|
||||
export default { en, sv }
|
||||
type LanguageKeys = keyof typeof en
|
||||
export type Languages = 'sv' | 'en'
|
||||
type Language = Record<LanguageKeys, string>
|
||||
|
||||
export default { en, sv } as Record<Languages, Language>
|
||||
|
|
|
@ -19,7 +19,6 @@ const sv = {
|
|||
via Patreon? Vi får väl se... Fram till den 29 april är appen gratis
|
||||
för både iOS och Android. Därefter måste vi bestämma oss för om det
|
||||
var en bra idé. Så tipsa alla dina vänner! Och stöd oss gärna på Patreon ❤️`,
|
||||
}
|
||||
} as const
|
||||
|
||||
export default sv
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ interface Event {
|
|||
export interface TimelineEvent {
|
||||
overview: ReactNode
|
||||
date: string
|
||||
importantDates?: Event[]
|
||||
media?: Event[]
|
||||
importantDates: Event[]
|
||||
media: Event[]
|
||||
}
|
||||
|
||||
export const events: TimelineEvent[] = [
|
||||
|
@ -488,6 +488,7 @@ export const events: TimelineEvent[] = [
|
|||
'Avslag på begäran om dokumentation med hänvisning till sekretess men utan lagrum',
|
||||
},
|
||||
],
|
||||
media: [],
|
||||
},
|
||||
{
|
||||
overview: (
|
||||
|
@ -505,5 +506,6 @@ export const events: TimelineEvent[] = [
|
|||
'Begäran om dokumentation av API (skickat till Kontaktcenter Stockholm)',
|
||||
},
|
||||
],
|
||||
media: [],
|
||||
},
|
||||
]
|
||||
|
|
|
@ -8,19 +8,19 @@ import { useRouter } from 'next/router'
|
|||
import { useEffect } from 'react'
|
||||
import { IntlProvider } from 'react-intl'
|
||||
import { pageview } from '../components/gtag'
|
||||
import messages from '../content/locale/'
|
||||
import messages, { Languages } from '../content/locale/'
|
||||
import { AppProps } from 'next/app'
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
export default function App({ Component, pageProps }: AppProps): JSX.Element {
|
||||
const router = useRouter()
|
||||
const { locale, defaultLocale } = router
|
||||
const { locale = 'sv', defaultLocale } = router
|
||||
|
||||
const currentMessages = messages[locale]
|
||||
const currentMessages = messages[locale as Languages]
|
||||
|
||||
// Google analytics
|
||||
useEffect(() => {
|
||||
const handleRouteChange = (url) => {
|
||||
pageview(url)
|
||||
}
|
||||
const handleRouteChange = (url: string) => pageview(url)
|
||||
|
||||
router.events.on('routeChangeComplete', handleRouteChange)
|
||||
return () => {
|
||||
router.events.off('routeChangeComplete', handleRouteChange)
|
||||
|
|
|
@ -2,7 +2,7 @@ import Timeline from '../components/Timeline'
|
|||
import { H1 } from '../components/Typography'
|
||||
import { events } from '../data/timelineEvents'
|
||||
|
||||
const CurrentEventsPage = () => {
|
||||
const CurrentEventsPage = (): JSX.Element => {
|
||||
return (
|
||||
<section className="mx-5 max-w-2xl md:mx-auto">
|
||||
<div className="my-8 md:my-20">
|
||||
|
|
|
@ -8,7 +8,7 @@ import PricingTemp from '../components/PricingTemp'
|
|||
import Testimonials from '../components/Testimonials'
|
||||
import TimelineLatest from '../components/TimelineLatest'
|
||||
|
||||
const HomePage = () => {
|
||||
const HomePage = (): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<Banner />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Privacy from '../components/Privacy'
|
||||
|
||||
const IntegrityPage = () => {
|
||||
const IntegrityPage = (): JSX.Element => {
|
||||
return <Privacy />
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import QA from '../components/QA'
|
||||
|
||||
const QAPage = () => {
|
||||
const QAPage = (): JSX.Element => {
|
||||
return <QA />
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Status from '../components/Status'
|
||||
|
||||
const StatusPage = () => {
|
||||
const StatusPage = (): JSX.Element => {
|
||||
return <Status />
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// test-utils.js
|
||||
import React from 'react'
|
||||
import { render as rtlRender } from '@testing-library/react'
|
||||
import React, { ReactNode } from 'react'
|
||||
import { render as rtlRender, RenderResult } from '@testing-library/react'
|
||||
import { IntlProvider } from 'react-intl'
|
||||
import messages from '../content/locale'
|
||||
import messages, { Languages } from '../content/locale'
|
||||
|
||||
function render(
|
||||
ui: React.ReactElement,
|
||||
{ locale = 'sv', ...renderOptions } = {}
|
||||
) {
|
||||
function Wrapper({ children }) {
|
||||
{ locale = 'sv' as Languages, ...renderOptions } = {}
|
||||
): RenderResult {
|
||||
function Wrapper({ children }: { children?: ReactNode }) {
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages[locale]}>
|
||||
{children}
|
||||
|
|
Loading…
Reference in New Issue