Skip to content

Commit

Permalink
[To Feature] DESENG-501 Added new content tabs to engagement form (#2427
Browse files Browse the repository at this point in the history
)

* Added new content tabs to engagement form
  • Loading branch information
VineetBala-AOT authored Mar 26, 2024
1 parent 29c2e00 commit 8404a01
Show file tree
Hide file tree
Showing 24 changed files with 1,234 additions and 61 deletions.
17 changes: 17 additions & 0 deletions met-web/src/apiManager/endpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ const Endpoints = {
GET: `${AppConfig.apiUrl}/slugs/slug_id`,
GET_ENG_ID: `${AppConfig.apiUrl}/slugs/engagements/engagement_id`,
},
EngagementContent: {
GET: `${AppConfig.apiUrl}/engagement/engagement_id/content`,
CREATE: `${AppConfig.apiUrl}/engagement/engagement_id/content`,
SORT: `${AppConfig.apiUrl}/engagement/engagement_id/content/sort_index`,
UPDATE: `${AppConfig.apiUrl}/engagement/engagement_id/content/content_id`,
DELETE: `${AppConfig.apiUrl}/engagement/engagement_id/content/content_id`,
},
EngagementCustomContent: {
GET: `${AppConfig.apiUrl}/content/content_id/custom`,
CREATE: `${AppConfig.apiUrl}/content/content_id/custom`,
UPDATE: `${AppConfig.apiUrl}/content/content_id/custom`,
},
EngagementSummaryContent: {
GET: `${AppConfig.apiUrl}/content/content_id/summary`,
CREATE: `${AppConfig.apiUrl}/content/content_id/summary`,
UPDATE: `${AppConfig.apiUrl}/content/content_id/summary`,
},
User: {
GET: `${AppConfig.apiUrl}/user/user_id`,
CREATE_UPDATE: `${AppConfig.apiUrl}/user/`,
Expand Down
28 changes: 28 additions & 0 deletions met-web/src/components/engagement/form/ActionContext.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { createContext, useState, useEffect, useMemo } from 'react';
import { postEngagement, getEngagement, patchEngagement } from '../../../services/engagementService';
import { getEngagementMetadata, getMetadataTaxa } from '../../../services/engagementMetadataService';
import { getEngagementContent } from 'services/engagementContentService';
import { useNavigate, useParams } from 'react-router-dom';
import { EngagementContext, EngagementForm, EngagementFormUpdate, EngagementParams } from './types';
import { createDefaultEngagement, Engagement, EngagementMetadata, MetadataTaxon } from '../../../models/engagement';
import { createDefaultEngagementContent, EngagementContent } from 'models/engagementContent';
import { saveObject } from 'services/objectStorageService';
import { openNotification } from 'services/notificationService/notificationSlice';
import { useAppDispatch, useAppSelector } from 'hooks';
Expand Down Expand Up @@ -51,6 +53,13 @@ export const ActionContext = createContext<EngagementContext>({
setIsNewEngagement: () => {
/* empty default method */
},
contentTabs: [createDefaultEngagementContent()],
setContentTabs: () => {
return;
},
fetchEngagementContents: async () => {
/* empty default method */
},
});

export const ActionProvider = ({ children }: { children: JSX.Element }) => {
Expand All @@ -70,6 +79,7 @@ export const ActionProvider = ({ children }: { children: JSX.Element }) => {
const [engagementMetadata, setEngagementMetadata] = useState<EngagementMetadata[]>([]);
const [bannerImage, setBannerImage] = useState<File | null>();
const [savedBannerImageFileName, setSavedBannerImageFileName] = useState('');
const [contentTabs, setContentTabs] = useState<EngagementContent[]>([createDefaultEngagementContent()]);

const isCreate = window.location.pathname.includes(CREATE);

Expand Down Expand Up @@ -126,6 +136,20 @@ export const ActionProvider = ({ children }: { children: JSX.Element }) => {
}
};

const fetchEngagementContents = async () => {
if (isCreate) {
return;
}

try {
const engagementContents = await getEngagementContent(Number(engagementId));
setContentTabs(engagementContents);
} catch (err) {
console.log(err);
dispatch(openNotification({ severity: 'error', text: 'Error Fetching Engagement Contents' }));
}
};

const taxonMetadata = useMemo(() => {
const taxonMetadataMap = new Map<number, string[]>();
engagementMetadata.forEach((metadata) => {
Expand Down Expand Up @@ -173,6 +197,7 @@ export const ActionProvider = ({ children }: { children: JSX.Element }) => {
const loadData = async () => {
await fetchEngagement();
await fetchEngagementMetadata();
await fetchEngagementContents();
setLoadingSavedEngagement(false);
};

Expand Down Expand Up @@ -275,6 +300,9 @@ export const ActionProvider = ({ children }: { children: JSX.Element }) => {
loadingAuthorization,
isNewEngagement,
setIsNewEngagement,
contentTabs,
setContentTabs,
fetchEngagementContents,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import React, { useContext, useEffect, useState } from 'react';
import { MenuItem, Modal, Grid, Stack, TextField, Select } from '@mui/material';
import { modalStyle, MetHeader1, MetLabel, PrimaryButton } from 'components/common';
import { useAppDispatch } from 'hooks';
import { openNotification } from 'services/notificationService/notificationSlice';
import { ActionContext } from '../../ActionContext';
import { EngagementContentContext } from './EngagementContentContext';
import { EngagementContent } from 'models/engagementContent';
import { postEngagementContent, patchEngagementContent } from 'services/engagementContentService';

interface ContentTabModalProps {
open: boolean;
updateModal: (open: boolean) => void;
tabs: EngagementContent[];
setTabs: React.Dispatch<React.SetStateAction<EngagementContent[]>>;
selectedTabType?: string;
tabIndex?: number;
}

const ContentTabModal = ({ open, updateModal, tabs, setTabs, selectedTabType, tabIndex }: ContentTabModalProps) => {
const { savedEngagement } = useContext(ActionContext);
const { isEditMode, setIsSummaryContentsLoading, setIsCustomContentsLoading } =
useContext(EngagementContentContext);
const dispatch = useAppDispatch();
const [tabTitle, setTabTitle] = useState('');
const [tabIcon, setTabIcon] = useState('');

useEffect(() => {
// Fetch tab details when modal is opened and selectedTabIndex changes
if (open && isEditMode && typeof tabIndex === 'number' && tabs[tabIndex]) {
setTabTitle(tabs[tabIndex].title);
setTabIcon(tabs[tabIndex].icon_name);
} else {
// If not in edit mode, initialize tabTitle and tabIcon with empty values
setTabTitle('');
setTabIcon('');
}
}, [open, isEditMode, tabIndex, tabs]);

const fetchData = async () => {
setIsSummaryContentsLoading(true);
setIsCustomContentsLoading(true);
const newtab = isEditMode
? await patchEngagementContent(savedEngagement.id, tabs[tabIndex || 0].id, {
title: tabTitle,
icon_name: tabIcon,
})
: await postEngagementContent(savedEngagement.id, {
title: tabTitle,
icon_name: tabIcon,
content_type: selectedTabType,
engagement_id: savedEngagement.id,
});

if (isEditMode) {
if (newtab && Object.keys(newtab).length !== 0) {
setTabs((prevTabs) => {
const newTabs = [...prevTabs];
newTabs[tabIndex || 0] = newtab;
return newTabs;
});
}
} else {
if (newtab && Object.keys(newtab).length !== 0) {
// Update the state by adding the new tab to the existing tabs
setTabs((prevTabs) => [...prevTabs, newtab]);
}
}

dispatch(
openNotification({
severity: 'success',
text: `Content tab successfully ${isEditMode ? 'updated' : 'created'}. Proceed to ${
isEditMode ? 'edit' : 'add'
} details.`,
}),
);
setIsSummaryContentsLoading(false);
setIsCustomContentsLoading(false);
handleModalClose();
};

const handleModalClose = () => {
updateModal(false);
setTabTitle('');
setTabIcon('');
};

return (
<Modal aria-labelledby="modal-title" open={open} onClose={() => updateModal(false)}>
<Grid
container
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
sx={{ ...modalStyle, overflowY: 'scroll' }}
rowSpacing={2}
>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<MetHeader1 bold sx={{ mb: 2 }} data-testid={isEditMode ? 'edit-tab' : 'add-tab'}>
{isEditMode ? 'Edit the engagement content tab' : 'Add a new engagement content tab'}
</MetHeader1>
</Stack>
</Grid>
<Grid container direction="row" item xs={12} alignItems="center">
<Grid item md={2} xs={12}>
<MetLabel align="left" marginBottom="1rem">
Tab Title:
</MetLabel>
</Grid>
<Grid item md={10} xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<TextField
id="content-tab-title"
data-testid="content-tab/title"
variant="outlined"
label=" "
InputLabelProps={{
shrink: false,
}}
fullWidth
sx={{ width: '100%' }}
name="content-tab-title"
value={tabTitle}
onChange={(e) => setTabTitle(e.target.value)}
error={tabTitle.length > 50}
helperText={
tabTitle.length > 50
? 'Title must not exceed 50 characters'
: 'Title must be specified'
}
size="small"
/>
</Stack>
</Grid>
</Grid>
<Grid container direction="row" item xs={12} alignItems="center">
<Grid item md={2} xs={12}>
<MetLabel align="left" marginBottom="1rem">
Tab Icon:
</MetLabel>
</Grid>
<Grid item md={10} xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<Select
name="content-tab-icon"
id="content-tab-icon"
data-testid="content-tab/icon"
variant="outlined"
value={tabIcon}
defaultValue="Select an tab icon"
fullWidth
sx={{ width: '100%' }}
onChange={(e) => setTabIcon(e.target.value)}
size="small"
>
<MenuItem value="">None</MenuItem>
<MenuItem value="faRectangleList">Rectangle-list</MenuItem>
<MenuItem value="faFileLines">File-lines</MenuItem>
</Select>
</Stack>
</Grid>
</Grid>
<Grid
container
direction="row"
item
xs={12}
justifyContent="flex-end"
alignItems="center"
sx={{ mt: '1em' }}
>
<PrimaryButton
variant="contained"
onClick={fetchData}
data-testid={isEditMode ? 'update-tab-button' : 'add-tab-button'}
>
{isEditMode ? 'Update Tab' : 'Add Tab'}
</PrimaryButton>
</Grid>
</Grid>
</Modal>
);
};

export default ContentTabModal;
Loading

0 comments on commit 8404a01

Please sign in to comment.