diff --git a/CHANGELOG.MD b/CHANGELOG.MD
index 031964adc..73d84fb5a 100644
--- a/CHANGELOG.MD
+++ b/CHANGELOG.MD
@@ -1,3 +1,7 @@
+## January 10, 2024
+
+- **Task** Custom Consent per Engagement [🎟️DESENG-456](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-456)
+
## January 9, 2024
- **Task** Improvements from Epic [🎟️DESENG-468](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-468)
diff --git a/met-api/migrations/versions/bd0eb0d25caf_adding_engagement_consent_message.py b/met-api/migrations/versions/bd0eb0d25caf_adding_engagement_consent_message.py
new file mode 100644
index 000000000..2d2ce9577
--- /dev/null
+++ b/met-api/migrations/versions/bd0eb0d25caf_adding_engagement_consent_message.py
@@ -0,0 +1,28 @@
+"""adding_engagement_consent_message
+
+Revision ID: bd0eb0d25caf
+Revises: 4114001e1a4c
+Create Date: 2024-01-10 12:21:32.781720
+
+"""
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import postgresql
+
+# revision identifiers, used by Alembic.
+revision = 'bd0eb0d25caf'
+down_revision = '4114001e1a4c'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('engagement', sa.Column('consent_message', postgresql.JSON(astext_type=sa.Text()), nullable=True))
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column('engagement', 'consent_message')
+ # ### end Alembic commands ###
diff --git a/met-api/src/met_api/models/engagement.py b/met-api/src/met_api/models/engagement.py
index 3a5980615..b122a2684 100644
--- a/met-api/src/met_api/models/engagement.py
+++ b/met-api/src/met_api/models/engagement.py
@@ -48,6 +48,7 @@ class Engagement(BaseModel):
status_block = db.relationship('EngagementStatusBlock', backref='engagement')
tenant_id = db.Column(db.Integer, db.ForeignKey('tenant.id'), nullable=True)
is_internal = db.Column(db.Boolean, nullable=False)
+ consent_message = db.Column(JSON, unique=False, nullable=True)
@classmethod
def get_engagements_paginated(
@@ -124,6 +125,7 @@ def update_engagement(cls, engagement: EngagementSchema) -> Engagement:
content=engagement.get('content', None),
rich_content=engagement.get('rich_content', None),
is_internal=engagement.get('is_internal', record.is_internal),
+ consent_message=engagement.get('consent_message', record.consent_message),
)
query.update(update_fields)
db.session.commit()
diff --git a/met-api/src/met_api/schemas/engagement.py b/met-api/src/met_api/schemas/engagement.py
index b1961b29e..9ef4db9b0 100644
--- a/met-api/src/met_api/schemas/engagement.py
+++ b/met-api/src/met_api/schemas/engagement.py
@@ -48,6 +48,7 @@ class Meta: # pylint: disable=too-few-public-methods
status_block = fields.List(fields.Nested(EngagementStatusBlockSchema))
tenant_id = fields.Str(data_key='tenant_id')
is_internal = fields.Bool(data_key='is_internal')
+ consent_message = fields.Str(data_key='consent_message')
def get_submissions_meta_data(self, obj):
"""Get the meta data of the submissions made in the survey."""
diff --git a/met-api/src/met_api/services/engagement_service.py b/met-api/src/met_api/services/engagement_service.py
index 0c75ab67f..4392da86b 100644
--- a/met-api/src/met_api/services/engagement_service.py
+++ b/met-api/src/met_api/services/engagement_service.py
@@ -183,7 +183,8 @@ def _create_engagement_model(engagement_data: dict) -> EngagementModel:
banner_filename=engagement_data.get('banner_filename', None),
content=engagement_data.get('content', None),
rich_content=engagement_data.get('rich_content', None),
- is_internal=engagement_data.get('is_internal', False)
+ is_internal=engagement_data.get('is_internal', False),
+ consent_message=engagement_data.get('consent_message', None)
)
new_engagement.save()
return new_engagement
diff --git a/met-web/src/components/FormCAC/FirstTab.tsx b/met-web/src/components/FormCAC/FirstTab.tsx
index 4e4186593..f62c90f87 100644
--- a/met-web/src/components/FormCAC/FirstTab.tsx
+++ b/met-web/src/components/FormCAC/FirstTab.tsx
@@ -8,6 +8,8 @@ import { useAppTranslation } from 'hooks';
import { FormContext } from './FormContext';
import { TAB_TWO } from './constants';
import { When } from 'react-if';
+import { Editor } from 'react-draft-wysiwyg';
+import { getEditorStateFromRaw } from 'components/common/RichTextEditor/utils';
// Define the Yup schema for validation
const schema = yup.object({
@@ -22,7 +24,7 @@ interface FormData {
export const FirstTab: React.FC = () => {
const { t: translate } = useAppTranslation();
- const { setTabValue, setFormSubmission } = useContext(FormContext);
+ const { consentMessage, setTabValue, setFormSubmission } = useContext(FormContext);
// Initialize form state and validation using react-hook-form
const {
@@ -86,11 +88,7 @@ export const FirstTab: React.FC = () => {
I understand that...
- Personal information is collected under Section 26(c) of the Freedom of Information and Protection of
- Privacy Act, for the purpose of participating in the Community Advisory Committee conducted by the
- Environmental Assessment Office. If you have any questions about the collection, use and disclosure of
- your personal information, please contact {translate('cacForm.contactTitle')} at{' '}
- {contactEmail}.
+
diff --git a/met-web/src/components/FormCAC/FormContext.tsx b/met-web/src/components/FormCAC/FormContext.tsx
index 4679aaceb..021ed7a59 100644
--- a/met-web/src/components/FormCAC/FormContext.tsx
+++ b/met-web/src/components/FormCAC/FormContext.tsx
@@ -29,6 +29,7 @@ export interface FormContextProps {
loading: boolean;
submitting: boolean;
setSubmitting: React.Dispatch>;
+ consentMessage: string;
}
export const FormContext = createContext({
@@ -52,6 +53,7 @@ export const FormContext = createContext({
setSubmitting: () => {
return;
},
+ consentMessage: '',
});
export const FormContextProvider = ({ children }: { children: JSX.Element }) => {
const { widgetId, engagementId } = useParams<{ widgetId: string; engagementId: string }>();
@@ -68,6 +70,7 @@ export const FormContextProvider = ({ children }: { children: JSX.Element }) =>
const [submitting, setSubmitting] = useState(false);
const [engagement, setEngagement] = useState(null);
const [engagementSlug, setEngagementSlug] = useState('');
+ const [consentMessage, setConsentMessage] = useState('');
const dispatch = useDispatch();
const navigate = useNavigate();
@@ -116,6 +119,7 @@ export const FormContextProvider = ({ children }: { children: JSX.Element }) =>
const loadData = async () => {
const engagement = await loadEngagement();
setEngagement(engagement ?? null);
+ setConsentMessage(engagement?.consent_message ?? '');
const subscribeWidget = await loadWidget();
verifyData(engagement, subscribeWidget);
loadEngagementSlug();
@@ -185,6 +189,7 @@ export const FormContextProvider = ({ children }: { children: JSX.Element }) =>
loading,
submitting,
setSubmitting,
+ consentMessage,
}}
>
{children}
diff --git a/met-web/src/components/engagement/form/EngagementFormTabs/EngagementTabsContext.tsx b/met-web/src/components/engagement/form/EngagementFormTabs/EngagementTabsContext.tsx
index 625e9b822..dfe748780 100644
--- a/met-web/src/components/engagement/form/EngagementFormTabs/EngagementTabsContext.tsx
+++ b/met-web/src/components/engagement/form/EngagementFormTabs/EngagementTabsContext.tsx
@@ -22,6 +22,7 @@ interface EngagementFormData {
description: string;
content: string;
is_internal: boolean;
+ consent_message: string;
}
interface EngagementSettingsFormData {
@@ -35,6 +36,7 @@ const initialEngagementFormData = {
description: '',
content: '',
is_internal: false,
+ consent_message: '',
};
interface EngagementFormError {
@@ -139,6 +141,7 @@ export const EngagementTabsContextProvider = ({ children }: { children: React.Re
description: savedEngagement.description || '',
content: savedEngagement.content || '',
is_internal: savedEngagement.is_internal || false,
+ consent_message: savedEngagement.consent_message || '',
});
const [richDescription, setRichDescription] = useState(savedEngagement?.rich_description || '');
const [richContent, setRichContent] = useState(savedEngagement?.rich_content || '');
diff --git a/met-web/src/components/engagement/form/EngagementFormTabs/Settings/ConsentMessage.tsx b/met-web/src/components/engagement/form/EngagementFormTabs/Settings/ConsentMessage.tsx
new file mode 100644
index 000000000..ef994ac46
--- /dev/null
+++ b/met-web/src/components/engagement/form/EngagementFormTabs/Settings/ConsentMessage.tsx
@@ -0,0 +1,31 @@
+import React, { useContext } from 'react';
+import { Box, Grid } from '@mui/material';
+import { MetHeader4 } from 'components/common';
+import { EngagementSettingsContext } from './EngagementSettingsContext';
+import RichTextEditor from 'components/common/RichTextEditor';
+
+const ConsentMessage = () => {
+ const { consentMessage, setConsentMessage } = useContext(EngagementSettingsContext);
+
+ const handleRichContentChange = (newState: string) => {
+ setConsentMessage(newState);
+ };
+
+ return (
+
+
+ Collection Notice/Consent Message
+
+
+
+
+
+
+
+ );
+};
+
+export default ConsentMessage;
diff --git a/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsContext.tsx b/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsContext.tsx
index 9412c5823..c7bb86e87 100644
--- a/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsContext.tsx
+++ b/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsContext.tsx
@@ -8,6 +8,8 @@ import { SubmissionStatus } from 'constants/engagementStatus';
export interface EngagementSettingsContextState {
isInternal: boolean;
setIsInternal: (isInternal: boolean) => void;
+ consentMessage: string;
+ setConsentMessage: (richContent: string) => void;
sendReport: boolean;
setSendReport: (sendReport: boolean) => void;
handleSaveSettings: () => void;
@@ -20,6 +22,10 @@ export const EngagementSettingsContext = createContext {
return;
},
+ consentMessage: '',
+ setConsentMessage: () => {
+ return;
+ },
sendReport: false,
setSendReport: () => {
return;
@@ -41,6 +47,7 @@ export const EngagementSettingsContextProvider = ({ children }: { children: Reac
const [isInternal, setIsInternal] = useState(savedIsInternal);
const [sendReport, setSendReport] = useState(Boolean(settings.send_report));
const [updatingSettings, setUpdatingSettings] = useState(false);
+ const [consentMessage, setConsentMessage] = useState(savedEngagement?.consent_message || '');
const handleUpdateEngagementMetadata = () => {
return handleUpdateEngagementMetadataRequest({
@@ -53,6 +60,7 @@ export const EngagementSettingsContextProvider = ({ children }: { children: Reac
return handleUpdateEngagementRequest({
...engagementFormData,
is_internal: isInternal,
+ consent_message: consentMessage,
});
};
@@ -89,6 +97,8 @@ export const EngagementSettingsContextProvider = ({ children }: { children: Reac
value={{
isInternal,
sendReport,
+ consentMessage,
+ setConsentMessage,
setIsInternal,
setSendReport,
handleSaveSettings,
diff --git a/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsForm.tsx b/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsForm.tsx
index 19b15506d..d1c5c4605 100644
--- a/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsForm.tsx
+++ b/met-web/src/components/engagement/form/EngagementFormTabs/Settings/EngagementSettingsForm.tsx
@@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Divider, Grid } from '@mui/material';
import { MetPaper, PrimaryButton } from 'components/common';
import EngagementInformation from './EngagementInformation';
+import ConsentMessage from './ConsentMessage';
import InternalEngagement from './InternalEngagement';
import SendReport from './SendReport';
import { EngagementSettingsContext } from './EngagementSettingsContext';
@@ -34,6 +35,12 @@ const EngagementSettingsForm = () => {
+
+
+
+
+
+
Save
diff --git a/met-web/src/components/engagement/form/types.ts b/met-web/src/components/engagement/form/types.ts
index d11342179..b389dca29 100644
--- a/met-web/src/components/engagement/form/types.ts
+++ b/met-web/src/components/engagement/form/types.ts
@@ -45,6 +45,7 @@ export interface EngagementFormUpdate {
rich_content?: string;
is_internal?: boolean;
status_block?: EngagementStatusBlock[];
+ consent_message?: string;
}
export type EngagementParams = {
diff --git a/met-web/src/components/engagement/view/EmailPanel.tsx b/met-web/src/components/engagement/view/EmailPanel.tsx
index 042ecce34..ef9a3f590 100644
--- a/met-web/src/components/engagement/view/EmailPanel.tsx
+++ b/met-web/src/components/engagement/view/EmailPanel.tsx
@@ -1,4 +1,5 @@
-import React, { FormEvent, useState } from 'react';
+import React, { FormEvent, useContext, useState } from 'react';
+import { ActionContext } from './ActionContext';
import { Grid, Checkbox, TextField, FormControl, FormControlLabel, FormHelperText, Stack, Link } from '@mui/material';
import { EmailPanelProps } from './types';
import {
@@ -13,8 +14,11 @@ import {
} from 'components/common';
import { When } from 'react-if';
import { INTERNAL_EMAIL_DOMAIN } from 'constants/emailVerification';
+import { Editor } from 'react-draft-wysiwyg';
+import { getEditorStateFromRaw } from 'components/common/RichTextEditor/utils';
const EmailPanel = ({ email, checkEmail, handleClose, updateEmail, isSaving, isInternal }: EmailPanelProps) => {
+ const { savedEngagement } = useContext(ActionContext);
const [checked, setChecked] = useState(false);
const [emailFormError, setEmailFormError] = useState({
terms: false,
@@ -82,18 +86,11 @@ const EmailPanel = ({ email, checkEmail, handleClose, updateEmail, isSaving, isI
- {`
- Personal information (your email address) is collected under Section 26(c) and 26(e) of the Freedom of Information\
- and Protection of Privacy Act, for the purpose of providing content updates and future opportunities to participate.\
- Your email is never shared with third parties.
- `}
-
-
- {
- 'If you have any questions about the collection, use and disclosure of your personal information,\
- please contact the Director of Digital Services at '
- }
- Sid.Tobias@gov.bc.ca
+
void }) => {
const dispatch = useAppDispatch();
@@ -106,27 +108,13 @@ const EmailListModal = ({ open, setOpen }: { open: boolean; setOpen: (open: bool
handleConfirm={sendEmail}
isSaving={isSaving}
termsOfService={
-
-
- Personal information is collected under Section 26(c) of the Freedom of Information and
- Protection of Privacy Act, for the purpose of providing content updates and future opportunities
- to participate in engagements, as well as for the purpose of providing general feedback to
- evaluate engagements conducted by the Environmental Assessment Office.
-
-
- If you have any questions about the collection, use and disclosure of your personal information,
- please contact the Director of Digital Services at{' '}
- Sid.Tobias@gov.bc.ca
-
-
+
+
+
}
header={'Sign Up for Updates'}
subText={[
diff --git a/met-web/src/models/engagement.ts b/met-web/src/models/engagement.ts
index 47f0b6909..70f6ee069 100644
--- a/met-web/src/models/engagement.ts
+++ b/met-web/src/models/engagement.ts
@@ -25,6 +25,7 @@ export interface Engagement {
submissions_meta_data: SurveySubmissionData;
status_block: EngagementStatusBlock[];
is_internal: boolean;
+ consent_message: string;
}
export interface Status {
@@ -71,6 +72,7 @@ export const createDefaultEngagement = (): Engagement => {
},
status_block: [],
is_internal: false,
+ consent_message: '',
};
};