Skip to content

Commit

Permalink
Add support for multiple projects: Keep data in projects array
Browse files Browse the repository at this point in the history
  • Loading branch information
mpgxvii committed Sep 10, 2024
1 parent f4cde4f commit a3c7906
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 55 deletions.
2 changes: 1 addition & 1 deletion pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const Home: NextPage = () => {
<div className="row">
<DocsButton
testid="study"
href="/study"
href="/study?projectId=STAGING_PROJECT"
disabled={hasSession}
title={"Study"}
/>
Expand Down
8 changes: 6 additions & 2 deletions pages/registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,16 @@ const Registration: NextPage = () => {
}, [flowId, router, router.isReady, returnTo, flow])

const onSubmit = async (values: UpdateRegistrationFlowBody) => {
const project = {
id: projectId,
name: projectId,
eligbility: JSON.parse(eligibility),
}
const updatedValues = {
...parseObject(values),
transient_payload: { project_id: projectId },
traits: {
...parseObject(values).traits,
eligibility: JSON.parse(eligibility),
projects: [project]
},
}
await router
Expand Down
14 changes: 13 additions & 1 deletion pages/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
SettingsFlow,
UiNodeInputAttributes,
UpdateSettingsFlowBody,
UpdateSettingsFlowWithProfileMethod,
} from "@ory/client"
Expand Down Expand Up @@ -54,6 +55,7 @@ const Settings: NextPage = () => {
const router = useRouter()
const { flow: flowId, return_to: returnTo } = router.query
const [email, setEmail] = useState("")
const [csrfToken, setCsrfToken] = useState("")

useEffect(() => {
// If the router is not ready yet, or we already have a flow, do nothing.
Expand All @@ -78,6 +80,12 @@ const Settings: NextPage = () => {
returnTo: String(returnTo || ""),
})
.then(({ data }) => {
const csrfTokenFromHeaders = (
data.ui.nodes.find(
(node: any) => node.attributes.name === "csrf_token",
)?.attributes as UiNodeInputAttributes
).value
setCsrfToken(csrfTokenFromHeaders || "")
setEmail(data.identity.traits.email)
setFlow(data)
})
Expand All @@ -93,7 +101,10 @@ const Settings: NextPage = () => {
ory
.updateSettingsFlow({
flow: String(flow?.id),
updateSettingsFlowBody: values,
updateSettingsFlowBody: {
...values,
'csrf_token': csrfToken
},
})
.then(({ data }) => {
// The settings have been saved and the flow was updated. Let's show it to the user!
Expand Down Expand Up @@ -143,6 +154,7 @@ const Settings: NextPage = () => {
</CardTitle>
<SettingsCard only="profile" flow={flow}>
<H3>Profile Settings</H3>
<Messages messages={flow?.ui.messages} />
<Flow
hideGlobalMessages
onSubmit={onSubmit}
Expand Down
145 changes: 94 additions & 51 deletions pages/study-consent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
SettingsFlow,
UiNodeInputAttributes,
UpdateSettingsFlowBody,
UpdateSettingsFlowWithProfileMethod,
} from "@ory/client"
import { H3, P } from "@ory/themes"
import { AxiosError } from "axios"
Expand Down Expand Up @@ -46,7 +45,7 @@ const StudyConsent: NextPage = () => {
const { flow: flowId, return_to: returnTo } = router.query
const [csrfToken, setCsrfToken] = useState<string>("")
const [traits, setTraits] = useState<any>()
const [consent, setConsent] = useState<any>({})
const [projects, setProjects] = useState<any>([])

useEffect(() => {
// If the router is not ready yet, or we already have a flow, do nothing.
Expand Down Expand Up @@ -80,33 +79,51 @@ const StudyConsent: NextPage = () => {
const traits = data.identity.traits
setCsrfToken(csrfTokenFromHeaders || "")
setTraits(traits)
setConsent(traits.consent)
setProjects(traits.projects)
})
.catch(handleFlowError(router, "settings", setFlow))
}, [flowId, router, router.isReady, returnTo, flow])

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setConsent({
...consent,
[event.target.name]: String(event.target.checked),
})
const handleChange = (
event: React.ChangeEvent<HTMLInputElement>,
projectId: string | null,
) => {
const { name, checked } = event.target

setProjects((prevProjects: any[]) =>
prevProjects.map((project) => {
if (project.id === projectId) {
return {
...project,
consent: {
...project.consent,
[name]: String(checked),
},
}
}
return project
}),
)
}

const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
const onSubmit = (
event: React.FormEvent<HTMLFormElement>,
projectId: string | null,
) => {
event.preventDefault()
const updatedValues: UpdateSettingsFlowBody = {
csrf_token: csrfToken,
method: "profile",
traits: {
...traits,
consent,
projects,
},
}

return (
router
// On submission, add the flow ID to the URL but do not navigate. This prevents the user loosing
// his data when she/he reloads the page.
// On submission, add the flow ID to the URL but do not navigate. This prevents the user losing
// their data when they reload the page.
.push(`/`)
.then(() =>
ory
Expand Down Expand Up @@ -150,7 +167,7 @@ const StudyConsent: NextPage = () => {
questions={consentQuestions}
onSubmit={onSubmit}
handleChange={handleChange}
consent={consent}
projects={projects}
/>
</StudyConsentCard>
<ActionCard wide>
Expand All @@ -162,50 +179,76 @@ const StudyConsent: NextPage = () => {
)
}

const ConsentForm: React.FC<any> = ({
interface ConsentFormProps {
questions: any[]
onSubmit: (
event: React.FormEvent<HTMLFormElement>,
projectId: string | null,
) => void
handleChange: (
event: React.ChangeEvent<HTMLInputElement>,
projectId: string | null,
) => void
projects: any[]
}

const ConsentForm: React.FC<ConsentFormProps> = ({
questions,
onSubmit,
handleChange,
consent,
projects,
}) => {
return (
<div className="center">
{questions.map((question: any, index: number) => {
if (question.field_type === "info") {
return (
question.select_choices_or_calculations instanceof Array &&
question.select_choices_or_calculations.map(
(info: any, idx: number) => (
<div key={`${index}-${idx}`}>
<label className="inputLabel">{info.code}</label>
<InnerCard>{info.label}</InnerCard>
</div>
),
)
)
} else if (question.field_type === "checkbox") {
return (
<form key={index} method="POST" onSubmit={onSubmit}>
<div className="consent-form">
<input
className="checkbox"
id={question.field_name}
name={question.field_name}
type="checkbox"
checked={consent && consent[question.field_name] === "true"}
onChange={handleChange}
/>
<label className="inputLabel inputLabelCheck">
{question.field_label}
</label>
</div>
<br />
<button type="submit">Save</button>
</form>
)
}
return null
})}
{projects.map((project) => (
<div key={project.id} className="project-form">
<h3>{project.name}</h3>
{questions.map((question, index) => {
if (question.field_type === "info") {
return (
question.select_choices_or_calculations instanceof Array &&
question.select_choices_or_calculations.map((info, idx) => (
<div key={`${index}-${idx}`}>
<label className="inputLabel">{info.code}</label>
<div className="inner-card">{info.label}</div>
<br />
</div>
))
)
} else if (question.field_type === "checkbox") {
return (
<form
key={index}
method="POST"
onSubmit={(event) => onSubmit(event, project.id)}
>
<div className="consent-form">
<input
className="checkbox"
id={question.field_name}
name={question.field_name}
type="checkbox"
checked={
project.consent &&
project.consent[question.field_name] === "true"
}
onChange={(event) => handleChange(event, project.id)}
/>
<br />
<br />
<label className="inputLabel inputLabelCheck">
{question.field_label}
</label>
</div>
<br />
<button type="submit">Save</button>
</form>
)
}
return null
})}
</div>
))}
</div>
)
}
Expand Down

0 comments on commit a3c7906

Please sign in to comment.