From 2c3d58e48e2d2a23d35fc1e0e8eb3871e8504a5b Mon Sep 17 00:00:00 2001
From: Nicholas <3789764+skykanin@users.noreply.github.com>
Date: Fri, 28 Jun 2024 07:04:07 +0000
Subject: [PATCH] update create team form (#280)
- 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) => (
+
+ ),
+ })
+
+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 (
-
- )
- },
- })
- )
-
-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 = () => (
+
+ )
+
+ 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)
)