Skip to content

Commit

Permalink
Merge branch 'develop' into 23-Subtitle-is-using-camelCase-as-subTitl…
Browse files Browse the repository at this point in the history
…e-in-Messages-created-on-portal
  • Loading branch information
pavliuc75 committed Nov 6, 2024
2 parents 19c02ef + 10dc1c3 commit 0327422
Show file tree
Hide file tree
Showing 44 changed files with 2,654 additions and 1,067 deletions.
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"i18n-ally.localesPaths": [
"src/locales"
],
"i18n-ally.keystyle": "nested",
}
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RUN npm install

COPY --chown=node:node app.js ./
COPY --chown=node:node .env ./
COPY --chown=node:node build/* ./build/
COPY --chown=node:node build/ ./build/

ENV PORT=8080

Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@
"formik": "^2.4.6",
"i18n-iso-countries": "^7.12.0",
"libphonenumber-js": "^1.11.11",
"i18next": "^23.15.1",
"i18next-http-backend": "^2.6.1",
"material-react-table": "^2.13.0",
"oidc-client-ts": "^3.0.1",
"papaparse": "^5.4.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-drag-drop-files": "^2.3.10",
"react-flags-select": "^2.2.3",
"react-i18next": "^15.0.1",
"react-oidc-context": "^3.1.0",
"react-router": "^6.23.1",
"react-router-dom": "^6.23.1",
Expand Down
1,819 changes: 974 additions & 845 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Binary file modified src/assets/images/ecg_heart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/ecg_heart_blue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/components/Buttons/CopyButton/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const StyledButton = styled(Button)(({ theme }) => ({
float: "right",
alignSelf: "flex-end",
color: theme.palette.primary.main,
cursor: "pointer",
}));

export default StyledButton;
47 changes: 47 additions & 0 deletions src/components/CarpAccordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { AccordionDetails, Stack } from "@mui/material";
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
import { ReactNode, useState } from "react";
import {
StyledAccordion,
StyledTypography,
SyledAccordionSummary,
Title,
} from "./styles";

type Props = {
title: string;
description?: string | null;
children: ReactNode;
};

const CarpAccordion = ({ title, description, children }: Props) => {
const [expanded, setExpanded] = useState(false);
const handleChange = () => {
setExpanded((prev) => !prev);
};

return (
<StyledAccordion elevation={2} onChange={handleChange} expanded={expanded}>
<SyledAccordionSummary
expandIcon={
<KeyboardArrowRightIcon
sx={{
transform: expanded ? "rotate(-270deg)" : "rotate(0deg)",
transition: "transform 0.3s ease",
}}
/>
}
>
<Stack direction="column" gap="10px">
<Title variant="h3">{title}</Title>
{description && expanded && (
<StyledTypography variant="h5">{description}</StyledTypography>
)}
</Stack>
</SyledAccordionSummary>
<AccordionDetails>{children}</AccordionDetails>
</StyledAccordion>
);
};

export default CarpAccordion;
28 changes: 28 additions & 0 deletions src/components/CarpAccordion/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Accordion, AccordionSummary, Typography } from "@mui/material";
import { styled } from "@Utils/theme";

export const StyledAccordion = styled(Accordion)(({ expanded }) => ({
padding: "10px 24px",
marginBottom: 32,
borderRadius: expanded ? 16 : 8,
transition: "border-radius 0.2s ease-in-out",
"::before": {
display: "none",
},
":last-of-type": {
borderRadius: expanded ? 16 : 8,
},
}));

export const SyledAccordionSummary = styled(AccordionSummary)({
padding: "0",
borderRadius: 16,
});

export const Title = styled(Typography)(({ theme }) => ({
color: theme.palette.primary.main,
}));

export const StyledTypography = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary,
}));
138 changes: 98 additions & 40 deletions src/components/SendReminderModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Modal, TextField, Typography } from "@mui/material";
import { useFormik } from "formik";
import { useEffect } from "react";
import * as yup from "yup";
import { GenericEmailRequest } from "@carp-dk/client/models/Email";
import { usePostEmailSendGeneric } from "@Utils/queries/participants";
import {
CancelButton,
TypographyVariant,
Content,
DoneButton,
HorizontalInputContainer,
HorizontalInputContainerWithAutoHeight,
ModalActions,
ModalBox,
Title,
Expand All @@ -16,39 +21,93 @@ type Props = {
open: boolean;
onClose: () => void;
to: string;
initials: string;
researcherEmail: string;
researcherName: string;
studyName: string;
};

const SendReminderModal = ({ open, onClose, to }: Props) => {
// const sendEmail = useSendEmail();
const validationSchema = yup.object({
message: yup.string().required("Message (email content) is required"),
subject: yup.string().required("Subject is required"),
cc: yup
.array()
.transform(function (value, originalValue) {
if (this.isType(value) && value !== null) {
return value;
}
return originalValue ? originalValue.split(/[\s,]+/) : [];
})
.of(yup.string().email(({ value }) => `${value} is not a valid email`)),
});

const SendReminderModal = ({
open,
onClose,
to,
initials,
researcherEmail,
researcherName,
studyName,
}: Props) => {
const postEmailSendGeneric = usePostEmailSendGeneric();

const convertTextareaInputToHtml = (str: string) => {
const urlRegex = /(https?:\/\/[^\s]+)/g;
const urlsWrappedIntoAnchorTags = str.replace(
urlRegex,
(url) => `<a href="${url}">${url}</a>`,
);
const withAddedBr = urlsWrappedIntoAnchorTags.replace(/\n/g, "<br>");
const wrappedInPre = `<pre style="white-space: pre-wrap;">${withAddedBr}</pre>`;

return wrappedInPre;
};

const reminderFormik = useFormik({
initialValues: {
cc: "",
message: `Dear Jakob Bardram,
cc: researcherEmail,
message: `Dear ${initials},
You have recently been invited to participate in the "${studyName}" study.
However, it appears that you have not yet joined the study on your phone. Your participation in this study is important to us and we would really appreciate your contribution.
If you haven't yet registered as a user or want to reset the password, please do it on this link - https://carp.computerome.dk/
If you have any questions, don't hesitate to contact me at this email address.
Kind regards,
${researcherName}
Kære ${initials},
Du er fornylig blevet inviteret til at deltage i "${studyName}" studiet.
Vi kan dog se, at du ikke har startet studiet på din telefon og vi vil meget gerne have at du kommer i gang. Studiet er vigtigt for os og det er vigtigt at du også deltager.
I am writing to remind you about the importance of uploading data to the Clinical Study, which is investigating the efficacy and safety in patients with cardiovascular disease. Your participation in this study contributes to our efforts in understanding and improving the treatment of cardiovascular disease.
Hvis du endnu ikke er oprettet som bruger, eller hvis du har glemt din password, kan du gøre det her - https://carp.computerome.dk/
Kindly click on the link below to be redirected to the study:
[Digital Tech Summit]
If you have any questions or encounter any difficulties while uploading the data, please do not hesitate to reach out to us for assistance.
[Researcher's Name][Researcher's Title/Position][Research Institution/Organization]
___________________________________________________
Study invitation
Hvis du har spørgsmål, så er du velkommen til at skrive til mig på denne mail adresse.
You are cordially invited to participate in the Clinical Study, investigating the efficacy and safety in patients with cardiovascular disease. Your participation in this study is important and will help us to better understand the potential benefits in treating cardiovascular disease.
`,
subject: "Reminder to participate in the XXX Study",
Med venlig hilsen
${researcherName}`,
subject: studyName,
},
onSubmit: (values) => {
// TODO: Send email
// eslint-disable-next-line no-console
console.log(values);
// TODO: Delete this after implementing the send email functionality
onClose();
const genericEmailRequest: GenericEmailRequest = {
recipient: to,
subject: values.subject,
message: convertTextareaInputToHtml(values.message),
cc: values.cc.split(/[\s,]+/).filter(Boolean),
};
postEmailSendGeneric.mutate(genericEmailRequest);
},
validationSchema,
});

useEffect(() => {
Expand All @@ -57,14 +116,9 @@ const SendReminderModal = ({ open, onClose, to }: Props) => {
};
}, [open]);

useEffect(
() => {
onClose();
},
[
/* sendEmail.isSuccess */
],
);
useEffect(() => {
onClose();
}, [postEmailSendGeneric.isSuccess]);

return (
<Modal
Expand All @@ -82,40 +136,43 @@ const SendReminderModal = ({ open, onClose, to }: Props) => {
</Typography>
<Typography variant="h5">{to}</Typography>
</HorizontalInputContainer>
<HorizontalInputContainer>
<Typography variant="h5" width="56px">
CC:
</Typography>
<HorizontalInputContainerWithAutoHeight>
<TypographyVariant variant="h5">CC:</TypographyVariant>
<TextField
type="text"
fullWidth
size="small"
name="cc"
placeholder='e.g. "alice@gmail.com, bob@gmail.com"'
helperText={reminderFormik.errors.cc}
error={!!reminderFormik.errors.cc}
value={reminderFormik.values.cc}
onChange={reminderFormik.handleChange}
/>
</HorizontalInputContainer>
<HorizontalInputContainer>
<Typography variant="h5" width="56px">
Subject:
</Typography>
</HorizontalInputContainerWithAutoHeight>
<HorizontalInputContainerWithAutoHeight>
<TypographyVariant variant="h5">Subject:</TypographyVariant>
<TextField
type="text"
fullWidth
size="small"
name="subject"
helperText={reminderFormik.errors.subject}
error={!!reminderFormik.errors.subject}
value={reminderFormik.values.subject}
onChange={reminderFormik.handleChange}
/>
</HorizontalInputContainer>
</HorizontalInputContainerWithAutoHeight>
<VerticalInputContainer>
<Typography variant="h5">Message:</Typography>
<TextField
type="text"
name="message"
fullWidth
multiline
rows={5}
rows={9}
helperText={reminderFormik.errors.message}
error={!!reminderFormik.errors.message}
value={reminderFormik.values.message}
onChange={reminderFormik.handleChange}
/>
Expand All @@ -126,6 +183,7 @@ const SendReminderModal = ({ open, onClose, to }: Props) => {
Cancel
</CancelButton>
<DoneButton
disabled={postEmailSendGeneric.isPending}
variant="contained"
sx={{ elevation: 0 }}
onClick={() => {
Expand Down
12 changes: 12 additions & 0 deletions src/components/SendReminderModal/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export const HorizontalInputContainer = styled("div")({
alignItems: "center",
});

export const HorizontalInputContainerWithAutoHeight = styled(
HorizontalInputContainer,
)({
height: "auto",
});

export const VerticalInputContainer = styled("div")({
display: "flex",
gap: 10,
Expand Down Expand Up @@ -64,3 +70,9 @@ export const DoneButton = styled(Button)(({ theme }) => ({
padding: "8px 24px",
borderRadius: 16,
}));

export const TypographyVariant = styled(Typography)(() => ({
marginTop: "10px",
marginBottom: "auto",
width: "56px",
}));
18 changes: 18 additions & 0 deletions src/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import backend from "i18next-http-backend";

i18n
.use(backend)
.use(initReactI18next)
.init({
supportedLngs: ["en", "da"],
lng: "en",
fallbackLng: "en",
ns: ["common", "error", "deployment"],
backend: {
loadPath: "/locales/{{lng}}/{{ns}}.json",
},
});

export default i18n;
Loading

0 comments on commit 0327422

Please sign in to comment.