From 34bf66f3805b079605c3a76df12ee479bfab91c0 Mon Sep 17 00:00:00 2001 From: Nicholas Jaunsen <3789764+skykanin@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:13:45 +0200 Subject: [PATCH] update create team form - supports section managers creating teams - redirects to new page on successful team creation - includes a link to the PR that is created --- src/App.tsx | 2 + src/pages/CreateTeamForm/CreateTeamForm.tsx | 84 +++++++++---------- .../CreateTeamForm/FormSubmissionError.tsx | 24 ++++++ .../CreateTeamForm/FormSubmissionResult.tsx | 37 -------- src/pages/CreateTeamForm/TeamCreated.tsx | 23 +++++ src/services/createTeam.ts | 18 ++-- 6 files changed, 102 insertions(+), 86 deletions(-) create mode 100644 src/pages/CreateTeamForm/FormSubmissionError.tsx delete mode 100644 src/pages/CreateTeamForm/FormSubmissionResult.tsx create mode 100644 src/pages/CreateTeamForm/TeamCreated.tsx diff --git a/src/App.tsx b/src/App.tsx index a78d090..ff8107c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import ProtectedRoute from './components/ProtectedRoute' import CreateTeamForm from './pages/CreateTeamForm/CreateTeamForm.tsx' +import TeamCreated from './pages/CreateTeamForm/TeamCreated.tsx' import NotFound from './pages/NotFound/NotFound.tsx' import TeamOverview from './pages/TeamOverview/TeamOverview' import UserProfile from './pages/UserProfile/UserProfile' @@ -20,6 +21,7 @@ const App = () => { } /> } /> } /> + } /> } /> diff --git a/src/pages/CreateTeamForm/CreateTeamForm.tsx b/src/pages/CreateTeamForm/CreateTeamForm.tsx index 818d98c..820dc78 100644 --- a/src/pages/CreateTeamForm/CreateTeamForm.tsx +++ b/src/pages/CreateTeamForm/CreateTeamForm.tsx @@ -15,12 +15,13 @@ import { import * as C from '@statisticsnorway/ssb-component-library' import { Skeleton } from '@mui/material' import { useEffect, useState, useMemo } from 'react' +import { useNavigate } from 'react-router-dom' import { Array as A, Console, Effect, Option as O, pipe } from 'effect' -import FormSubmissionResult, { FormSubmissionResultProps } from './FormSubmissionResult.tsx' +import FormSubmissionError, { FormSubmissionErrorProps } from './FormSubmissionError.tsx' import PageLayout from '../../components/PageLayout/PageLayout' import * as Klass from '../../services/klass' -import { AutonomyLevel, CreateTeamRequest, createTeam } from '../../services/createTeam' +import { AutonomyLevel, CreateTeamRequest, CreateTeamResponse, createTeam } from '../../services/createTeam' import { User } from '../../@types/user' import * as Utils from '../../utils/utils.ts' @@ -41,6 +42,7 @@ interface FormError { } const CreateTeamForm = () => { + const navigate = useNavigate() const uniformNameLengthLimit = 17 // TODO: These should be fetched from the dapla-team-api instead of being hardcoded const teamAutonomyLevels: DisplayAutonomyLevel[] = [ @@ -81,21 +83,11 @@ const CreateTeamForm = () => { const [submitButtonClicked, setSubmitButtonClicked] = useState(false) + const [createTeamResponseLoading, setCreateTeamResponseLoading] = useState(false) + const missingFieldErrorMessage = 'mangler' const validationErrorMessage = 'har en valideringsfeil' - const resetForm = () => { - setDisplayName('') - setUniformName('') - setOverrideUniformName(false) - setUniformNameErrorMsg('') - setSelectedSection(O.none()) - - setSelectedAutonomyLevel(teamAutonomyLevels[0]) - setAdditionalInformation('') - setSubmitButtonClicked(false) - } - const formErrors: FormError[] = useMemo( () => pipe( @@ -117,9 +109,8 @@ const CreateTeamForm = () => { [displayName, uniformName, selectedSection, uniformNameErrorMsg] ) - const [formSubmissionResult, setFormSubmissionResult] = useState({ - loading: false, - formSubmissionResult: O.none(), + const [formSubmissionError, setFormSubmissionError] = useState({ + formSubmissionError: O.none(), }) useEffect(() => { @@ -153,50 +144,55 @@ const CreateTeamForm = () => { event.preventDefault() // Only submit the form if no form errors are present if (A.isEmptyArray(formErrors)) { - const userPrincipalName = O.getOrThrow(user).principal_name const req: CreateTeamRequest = { teamDisplayName: displayName, uniformTeamName: uniformName, sectionCode: O.getOrThrow(selectedSection).id.toString(), - additionalInformation: `This PR was created through Dapla Ctrl. Additional information from user ${userPrincipalName}:\n ${additionalInformation}`, + additionalInformation: `This PR was created through Dapla Ctrl. Additional information from author:\n\n ${additionalInformation}`, autonomyLevel: selectedAutonomyLevel.id, features: [], } - setFormSubmissionResult({ loading: true, formSubmissionResult: O.none() }) + setCreateTeamResponseLoading(true) + setFormSubmissionError({ formSubmissionError: O.none() }) Effect.gen(function* () { - const clientResponse = yield* createTeam(req) - yield* Console.log('ClientResponse', clientResponse) - return O.some( - clientResponse.status !== 200 - ? { - success: false, - message: `Det oppstod en feil ved opprettelse av team. Statuskode: ${clientResponse.status}`, - } - : { success: true, message: 'Opprettelse av team ble registert.' } - ) + const createTeamResponse = yield* createTeam(req) + yield* Console.log('CreateTeamResponse:', createTeamResponse) + return { + success: true, + message: 'Opprettelse av team ble registert.', + body: O.some(createTeamResponse), + } }) .pipe( Effect.catchTags({ - ResponseError: (error) => Effect.succeed(O.some({ success: false, message: error.message })), - RequestError: (error) => Effect.succeed(O.some({ success: false, message: error.message })), + ResponseError: (error) => Effect.succeed({ success: false, message: error.message, body: O.none() }), + RequestError: (error) => Effect.succeed({ success: false, message: error.message, body: O.none() }), BodyError: (error) => - Effect.succeed(O.some({ success: false, message: `Failed to parse body: ${error.reason._tag}` })), + Effect.succeed({ + success: false, + message: `Failed to parse http request body: ${error.reason._tag}`, + body: O.none(), + }), + ParseError: (error) => + Effect.succeed({ + success: false, + message: `Failed to parse http response: ${error.message}`, + body: O.none(), + }), }), Effect.runPromise ) - .then((res: O.Option<{ success: boolean; message: string }>) => { - if ( - Utils.option( - res, - () => false, - (r) => r.success - ) - ) { - resetForm() + .then((result: { success: boolean; message: string; body: O.Option }) => { + if (result.success) { + navigate('/opprett-team/suksess', { + replace: true, + state: { kubenPullRequestUrl: O.getOrThrow(result.body).kubenPullRequestUrl }, + }) + } else { + setFormSubmissionError({ formSubmissionError: O.some(result.message) }) } - setFormSubmissionResult({ loading: false, formSubmissionResult: res }) }) } } @@ -359,7 +355,7 @@ const CreateTeamForm = () => { )} - + {createTeamResponseLoading && } ) diff --git a/src/pages/CreateTeamForm/FormSubmissionError.tsx b/src/pages/CreateTeamForm/FormSubmissionError.tsx new file mode 100644 index 0000000..a85c757 --- /dev/null +++ b/src/pages/CreateTeamForm/FormSubmissionError.tsx @@ -0,0 +1,24 @@ +import styles from './createTeamForm.module.scss' +import { Dialog } from '@statisticsnorway/ssb-component-library' +import { Option as O } from 'effect' +import { CircularProgress } from '@mui/material' + +export interface FormSubmissionErrorProps { + formSubmissionError: O.Option +} + +const FormSubmissionError = ({ formSubmissionError }: FormSubmissionErrorProps) => + O.match(formSubmissionError, { + onNone: () => ( +
+ +
+ ), + onSome: (errorMessage) => ( + + {errorMessage} + + ), + }) + +export default FormSubmissionError diff --git a/src/pages/CreateTeamForm/FormSubmissionResult.tsx b/src/pages/CreateTeamForm/FormSubmissionResult.tsx deleted file mode 100644 index 5406dcc..0000000 --- a/src/pages/CreateTeamForm/FormSubmissionResult.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import styles from './createTeamForm.module.scss' -import { Dialog } from '@statisticsnorway/ssb-component-library' -import { Option as O } from 'effect' -import { CircularProgress } from '@mui/material' - -export interface FormSubmissionResult { - readonly success: boolean - readonly message: string -} - -export interface FormSubmissionResultProps { - loading: boolean - formSubmissionResult: O.Option -} - -// -const FormSubmissionResult = ({ formSubmissionResult, loading }: FormSubmissionResultProps) => - loading ? ( -
- -
- ) : ( - O.match(formSubmissionResult, { - onNone: () => undefined, - onSome: (res) => { - const title = res.success ? 'Skjema ble innsendt' : 'Feil oppstod ved innsending av skjema' - const dialogType = res.success ? 'info' : 'warning' - return ( - - {res.message} - - ) - }, - }) - ) - -export default FormSubmissionResult diff --git a/src/pages/CreateTeamForm/TeamCreated.tsx b/src/pages/CreateTeamForm/TeamCreated.tsx new file mode 100644 index 0000000..7cc8a1a --- /dev/null +++ b/src/pages/CreateTeamForm/TeamCreated.tsx @@ -0,0 +1,23 @@ +import { Dialog, Link } from '@statisticsnorway/ssb-component-library' +import { useLocation } from 'react-router-dom' + +import PageLayout from '../../components/PageLayout/PageLayout' +import styles from './createTeamForm.module.scss' + +export interface TeamCreatedProps { + kubenPullRequestUrl: string +} + +const TeamCreated = () => { + const { state }: { state: TeamCreatedProps } = useLocation() + const renderContent = () => ( + + {`Opprettelse av team ble registert. Prosessen kan følges `} + her + + ) + + return +} + +export default TeamCreated diff --git a/src/services/createTeam.ts b/src/services/createTeam.ts index 12146a5..96b6af4 100644 --- a/src/services/createTeam.ts +++ b/src/services/createTeam.ts @@ -1,8 +1,8 @@ import { Effect } from 'effect' -import { Schema } from '@effect/schema' +import { ParseResult, Schema } from '@effect/schema' import * as Http from '@effect/platform/HttpClient' import { HttpClientError } from '@effect/platform/Http/ClientError' -import { ClientResponse } from '@effect/platform/Http/ClientResponse' +import * as ClientResponse from '@effect/platform/Http/ClientResponse' import { BodyError } from '@effect/platform/Http/Body' import { DAPLA_TEAM_API_URL } from '../utils/utils' import { withKeyEncoding } from '../utils/schema' @@ -26,13 +26,21 @@ export type AutonomyLevel = Schema.Schema.Type export type Feature = Schema.Schema.Type export type CreateTeamRequest = Schema.Schema.Type +const CreateTeamResponse = Schema.Struct({ + uniformTeamName: withKeyEncoding('uniform_team_name', Schema.String), + kubenPullRequestId: withKeyEncoding('kuben_pull_request_id', Schema.Number), + kubenPullRequestUrl: withKeyEncoding('kuben_pull_request_url', Schema.String), +}) + +export type CreateTeamResponse = Schema.Schema.Type + export const createTeam = ( createTeamRequest: CreateTeamRequest -): Effect.Effect => +): Effect.Effect => Http.request .post(new URL(CREATE_TEAM_URL, window.location.origin)) .pipe( Http.request.schemaBody(CreateTeamRequestSchema)(createTeamRequest), - Effect.flatMap(Http.client.fetch), - Effect.scoped + Effect.flatMap(Http.client.fetchOk), + ClientResponse.schemaBodyJsonScoped(CreateTeamResponse) )