Skip to content

Commit

Permalink
Merge pull request #912 from digitalfabrik/move-responsive-components…
Browse files Browse the repository at this point in the history
…-into-separate-folder

Create directory for responsive components
  • Loading branch information
sarahsporck authored Apr 11, 2023
2 parents 710899f + 1b1337c commit 85f0120
Show file tree
Hide file tree
Showing 87 changed files with 205 additions and 148 deletions.
42 changes: 42 additions & 0 deletions administration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Administration (Digitale Druckerei)

The administration project contains the React frontends for three audiences:

- Applicants can apply for an entitlementcard
- Organizations can verify or reject application details
- Administrators can manage applications, cards, and regions.

# Folder Structure

The administration frontend relies on [Blueprint](https://blueprintjs.com) and the [Material UI](https://mui.com) library. The latter is used for sites that need to be responsive, i.e. sites targeting applicants and organizations.
To keep the usage of the libraries separated (to keep a unified look and feel) the folder structure looks as follows:

- src
- bp-modules
- module A
- hooks \*
- util \*
- ...components
- module B
- hooks \*
- util \*
- ...components
- hooks \*
- util \*
- ...general components
- mui-modules
- module A
- hooks \*
- util \*
- ...components
- module B
- hooks \*
- util \*
- ...components
- hooks \*
- util \*
- ...general components
- ...global modules
- ...global components

(the \* refers to optional compontents)
31 changes: 17 additions & 14 deletions administration/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import React from 'react'
import AuthProvider from './AuthProvider'
import { ProjectConfigProvider } from './project-configs/ProjectConfigContext'
import MetaTagsManager from './components/MetaTagsManager'
import { AppToasterProvider } from './components/AppToaster'
import { AppToasterProvider } from './bp-modules/AppToaster'
import AppApolloProvider from './AppApolloProvider'
import Router from './Router'
import useMetaTags from './hooks/useMetaTags'

if (!process.env.REACT_APP_API_BASE_URL) {
throw new Error('REACT_APP_API_BASE_URL is not set!')
}

const App = () => (
<ProjectConfigProvider>
<MetaTagsManager />
<AppToasterProvider>
<AuthProvider>
<AppApolloProvider>
<Router />
</AppApolloProvider>
</AuthProvider>
</AppToasterProvider>
</ProjectConfigProvider>
)
const App = () => {
useMetaTags()

return (
<ProjectConfigProvider>
<AppToasterProvider>
<AuthProvider>
<AppApolloProvider>
<Router />
</AppApolloProvider>
</AuthProvider>
</AppToasterProvider>
</ProjectConfigProvider>
)
}

export default App
4 changes: 2 additions & 2 deletions administration/src/KeepAliveToken.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Button, Classes, Dialog } from '@blueprintjs/core'
import React, { ReactNode, useContext, useEffect, useState } from 'react'
import { TokenPayload } from './AuthProvider'
import { useAppToaster } from './components/AppToaster'
import { useAppToaster } from './bp-modules/AppToaster'
import { SignInPayload, useSignInMutation } from './generated/graphql'
import PasswordInput from './components/PasswordInput'
import PasswordInput from './bp-modules/PasswordInput'
import { ProjectConfigContext } from './project-configs/ProjectConfigContext'
import { WhoAmIContext } from './WhoAmIProvider'
import { useNavigate } from 'react-router-dom'
Expand Down
28 changes: 14 additions & 14 deletions administration/src/Router.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import React, { useContext, useMemo } from 'react'
import Navigation from './components/Navigation'
import Navigation from './bp-modules/NavigationBar'
import { createBrowserRouter, Outlet, RouteObject, RouterProvider } from 'react-router-dom'
import CreateCardsController from './components/cards/CreateCardsController'
import CreateCardsController from './bp-modules/cards/CreateCardsController'
import styled from 'styled-components'
import WhoAmIProvider from './WhoAmIProvider'
import { AuthContext } from './AuthProvider'
import Login from './components/auth/Login'
import Login from './bp-modules/auth/Login'
import KeepAliveToken from './KeepAliveToken'
import ApplicationsController from './components/applications/ApplicationsController'
import ApplicationsController from './bp-modules/applications/ApplicationsController'
import { ProjectConfigContext } from './project-configs/ProjectConfigContext'
import HomeController from './components/home/HomeController'
import RegionsController from './components/regions/RegionController'
import UserSettingsController from './components/user-settings/UserSettingsController'
import ResetPasswordController from './components/auth/ResetPasswordController'
import ForgotPasswordController from './components/auth/ForgotPasswordController'
import ManageUsersController from './components/users/ManageUsersController'
import ApplyController from './application/components/ApplyController'
import DataPrivacyPolicy from './components/DataPrivacyPolicy'
import ApplicationVerificationController from './application-verification/VerificationController'
import ApplicationApplicantController from './components/applications/ApplicationApplicantController'
import HomeController from './bp-modules/home/HomeController'
import RegionsController from './bp-modules/regions/RegionController'
import UserSettingsController from './bp-modules/user-settings/UserSettingsController'
import ResetPasswordController from './bp-modules/auth/ResetPasswordController'
import ForgotPasswordController from './bp-modules/auth/ForgotPasswordController'
import ManageUsersController from './bp-modules/users/ManageUsersController'
import DataPrivacyPolicy from './bp-modules/regions/DataPrivacyPolicy'
import ApplicationApplicantController from './mui-modules/application-verification/ApplicationApplicantController'
import ApplicationVerificationController from './mui-modules/application-verification/ApplicationVerificationController'
import ApplyController from './mui-modules/application/ApplyController'

const Main = styled.div`
flex-grow: 1;
Expand Down
2 changes: 1 addition & 1 deletion administration/src/WhoAmIProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, Spinner } from '@blueprintjs/core'
import { createContext, ReactNode, useContext } from 'react'
import { useWhoAmIQuery, WhoAmIQuery } from './generated/graphql'
import { ProjectConfigContext } from './project-configs/ProjectConfigContext'
import StandaloneCenter from './components/StandaloneCenter'
import StandaloneCenter from './bp-modules/StandaloneCenter'
import { AuthContext } from './AuthProvider'

export const WhoAmIContext = createContext<{
Expand Down
23 changes: 23 additions & 0 deletions administration/src/bp-modules/ErrorHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { ReactElement } from 'react'
import { Button, NonIdealState } from '@blueprintjs/core'

type ErrorHandlerProps = {
title?: string
description?: string | ReactElement
refetch: () => void
}

const ErrorHandler = ({
refetch,
title = 'Ein Fehler ist aufgetreten.',
description,
}: ErrorHandlerProps): ReactElement => (
<NonIdealState
icon={'error'}
title={title}
description={description}
action={<Button onClick={() => refetch()}>Erneut Versuchen</Button>}
/>
)

export default ErrorHandler
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { NonIdealState, Spinner } from '@blueprintjs/core'
import { WhoAmIContext } from '../../WhoAmIProvider'
import ApplicationsOverview from './ApplicationsOverview'
import { Region, useGetApplicationsQuery } from '../../generated/graphql'
import ErrorHandler from '../../ErrorHandler'
import ErrorHandler from '../ErrorHandler'

const ApplicationsController = (props: { region: Region }) => {
const { loading, error, data, refetch } = useGetApplicationsQuery({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { useAppToaster } from '../AppToaster'
import { useCheckPasswordResetLinkQuery, useResetPasswordMutation } from '../../generated/graphql'
import PasswordInput from '../PasswordInput'
import validateNewPasswordInput from './validateNewPasswordInput'
import ErrorHandler from '../../ErrorHandler'
import getMessageFromApolloError from '../errors/getMessageFromApolloError'
import ErrorHandler from '../ErrorHandler'
import getMessageFromApolloError from '../../errors/getMessageFromApolloError'

const ResetPasswordController = () => {
const config = useContext(ProjectConfigContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactElement, useContext } from 'react'
import styled from 'styled-components'
import { ProjectConfigContext } from '../project-configs/ProjectConfigContext'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'

const Container = styled.div`
max-width: 750px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { ReactElement, useContext } from 'react'
import { WhoAmIContext } from '../../WhoAmIProvider'
import RegionOverview from './RegionOverview'
import { Role, useGetDataPolicyQuery } from '../../generated/graphql'
import ErrorHandler from '../../ErrorHandler'
import ErrorHandler from '../ErrorHandler'
import { NonIdealState, Spinner } from '@blueprintjs/core'

const RegionController = ({ regionId }: { regionId: number }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Role, useCreateAdministratorMutation } from '../../generated/graphql'
import { useAppToaster } from '../AppToaster'
import RoleHelpButton from './RoleHelpButton'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'
import RegionSelector from '../RegionSelector'
import RegionSelector from './RegionSelector'
import RoleSelector from './RoleSelector'
import getMessageFromApolloError from '../errors/getMessageFromApolloError'
import getMessageFromApolloError from '../../errors/getMessageFromApolloError'

const RoleFormGroupLabel = styled.span`
& span {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useAppToaster } from '../AppToaster'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'
import { AuthContext } from '../../AuthProvider'
import { WhoAmIContext } from '../../WhoAmIProvider'
import getMessageFromApolloError from '../errors/getMessageFromApolloError'
import getMessageFromApolloError from '../../errors/getMessageFromApolloError'

const DeleteUserDialog = ({
selectedUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { Administrator, Role, useEditAdministratorMutation } from '../../generat
import { useAppToaster } from '../AppToaster'
import RoleHelpButton from './RoleHelpButton'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'
import RegionSelector from '../RegionSelector'
import RegionSelector from './RegionSelector'
import RoleSelector from './RoleSelector'
import { WhoAmIContext } from '../../WhoAmIProvider'
import getMessageFromApolloError from '../errors/getMessageFromApolloError'
import getMessageFromApolloError from '../../errors/getMessageFromApolloError'

const RoleFormGroupLabel = styled.span`
& span {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Card, H3, NonIdealState, Spinner } from '@blueprintjs/core'
import { Card, H3, NonIdealState, Spinner } from '@blueprintjs/core'
import { ReactElement, useContext } from 'react'
import {
Region,
Expand All @@ -11,17 +11,7 @@ import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext
import StandaloneCenter from '../StandaloneCenter'
import UsersTable from './UsersTable'
import { WhoAmIContext } from '../../WhoAmIProvider'

const RefetchCard = (props: { refetch: () => void }) => {
return (
<Card>
Etwas ist schief gelaufen.
<Button intent='primary' onClick={() => props.refetch()}>
Erneut versuchen
</Button>
</Card>
)
}
import ErrorHandler from '../ErrorHandler'

const UsersTableContainer = ({ children, title }: { children: ReactElement; title: string }) => {
return (
Expand All @@ -42,9 +32,9 @@ const ManageProjectUsers = () => {
if (regionsQuery.loading || usersQuery.loading) {
return <Spinner />
} else if (!regionsQuery.data || regionsQuery.error) {
return <RefetchCard refetch={regionsQuery.refetch} />
return <ErrorHandler refetch={regionsQuery.refetch} />
} else if (!usersQuery.data || usersQuery.error) {
return <RefetchCard refetch={usersQuery.refetch} />
return <ErrorHandler refetch={usersQuery.refetch} />
}

const regions = regionsQuery.data!!.regions
Expand All @@ -65,9 +55,9 @@ const ManageRegionUsers = ({ region }: { region: Region }) => {
if (regionsQuery.loading || usersQuery.loading) {
return <Spinner />
} else if (!regionsQuery.data || regionsQuery.error) {
return <RefetchCard refetch={regionsQuery.refetch} />
return <ErrorHandler refetch={regionsQuery.refetch} />
} else if (!usersQuery.data || usersQuery.error) {
return <RefetchCard refetch={usersQuery.refetch} />
return <ErrorHandler refetch={usersQuery.refetch} />
}

const regions = regionsQuery.data!!.regions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext, useMemo } from 'react'
import { Button, Menu, Spinner } from '@blueprintjs/core'
import { Classes, ItemListRenderer, ItemRenderer, Select } from '@blueprintjs/select'
import { Region, useGetRegionsQuery } from '../generated/graphql'
import { ProjectConfigContext } from '../project-configs/ProjectConfigContext'
import { Region, useGetRegionsQuery } from '../../generated/graphql'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'

const RegionSelect = Select.ofType<Region>()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ApolloError } from '@apollo/client'
import { ReactNode } from 'react'
import { ReactElement } from 'react'
import InvalidPasswordResetLink from './templates/InvalidPasswordResetLink'
import PasswordResetKeyExpired from './templates/PasswordResetKeyExpired'
import InvalidLink from './templates/InvalidLink'

type GraphQLErrorMessage = {
title: string
description?: string | ReactNode
description?: string | ReactElement
}
const getMessageFromApolloError = (error: ApolloError): GraphQLErrorMessage => {
const defaultMessage = 'Etwas ist schief gelaufen.'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useContext, useEffect } from 'react'
import { ProjectConfigContext } from '../project-configs/ProjectConfigContext'

const MetaTagsManager = () => {
const useMetaTags = () => {
const config = useContext(ProjectConfigContext)
useEffect(() => {
document.title = config.name + ' Verwaltung'
Expand All @@ -14,7 +14,6 @@ const MetaTagsManager = () => {
}
iconLink.href = '/icons/' + config.projectId + '.png'
}, [config])
return null
}

export default MetaTagsManager
export default useMetaTags
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Button, Card, Typography } from '@mui/material'
import React, { ReactElement, ReactNode } from 'react'
import React, { ReactElement } from 'react'
import { styled } from '@mui/system'

type ErrorHandlerProps = {
title?: string
description?: string | ReactNode
description?: string | ReactElement
refetch: () => void
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { useState } from 'react'

import ErrorHandler from '../../ErrorHandler'
import ErrorHandler from '../ErrorHandler'
import { useParams } from 'react-router-dom'
import styled from 'styled-components'
import { useGetApplicationByApplicantQuery } from '../../generated/graphql'
import ApplicationApplicantView from './ApplicationApplicantView'
import { Alert, CircularProgress } from '@mui/material'
import { SnackbarProvider } from 'notistack'
import getMessageFromApolloError from '../errors/getMessageFromApolloError'
import getMessageFromApolloError from '../../errors/getMessageFromApolloError'

const CenteredMessage = styled(Alert)`
margin: auto;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { ReactElement, useContext, useState } from 'react'
import { Application } from './ApplicationsOverview'
import VerificationsView from './VerificationsView'
import JsonFieldView, { GeneralJsonField } from './JsonFieldView'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'
import { useWithdrawApplicationMutation } from '../../generated/graphql'

import { styled } from '@mui/system'
import { Button, Card, CircularProgress, Divider, Typography } from '@mui/material'
import ConfirmDialog from '../../application/components/ConfirmDialog'
import ConfirmDialog from '../application/ConfirmDialog'
import { Delete } from '@mui/icons-material'
import { useSnackbar } from 'notistack'
import formatDateWithTimezone from '../../util/formatDate'
import JsonFieldView, { GeneralJsonField } from '../../bp-modules/applications/JsonFieldView'
import VerificationsView from '../../bp-modules/applications/VerificationsView'
import { Application } from '../../bp-modules/applications/ApplicationsOverview'
import getApiBaseUrl from '../../util/getApiBaseUrl'

const ApplicationViewCard = styled(Card)`
Expand Down
Loading

0 comments on commit 85f0120

Please sign in to comment.