Skip to content

Commit

Permalink
Merge pull request #356 from hotosm/feat/regulators-approval-flow
Browse files Browse the repository at this point in the history
Feat: Enhancements to Regulators Approval Flow on project creation
  • Loading branch information
subashtiwari1010 authored Nov 27, 2024
2 parents 5da527a + f766b83 commit 32f9d91
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,13 @@ const MapSection = ({ projectData }: { projectData: Record<string, any> }) => {
map={map as Map}
popupUI={getPopupUI}
title={`Task #${selectedTaskId}`}
showPopup={(feature: Record<string, any>) =>
feature?.source?.includes('tasks-layer')
}
showPopup={(feature: Record<string, any>) => {
if (!userDetails) return false;
return (
feature?.source?.includes('tasks-layer') &&
!userDetails?.role?.includes('REGULATOR') // Don't show popup if user role is regulator
);
}}
fetchPopupData={(properties: Record<string, any>) => {
dispatch(
setProjectState({
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/src/components/LandingPage/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import arrowSouth from '@Assets/images/LandingPage/arrow_south.svg';
import { setCommonState } from '@Store/actions/common';
import useAuth from '@Hooks/useAuth';
import { useNavigate } from 'react-router-dom';
import { getLocalStorageValue } from '@Utils/getLocalStorageValue';

export default function Home() {
const dispatch = useTypedDispatch();
const { isAuthenticated } = useAuth();
const navigate = useNavigate();
const userProfile = getLocalStorageValue('userprofile');

const bounceTransition: {
y: {
Expand Down Expand Up @@ -52,7 +54,7 @@ export default function Home() {
<div className="naxatw-container naxatw-h-full !naxatw-max-w-full naxatw-py-12">
<div className="naxatw-flex naxatw-animate-fade-up naxatw-flex-row naxatw-justify-between">
<Image src={droneTaskingManagerLogo} />
{isAuthenticated() ? (
{isAuthenticated() && !userProfile?.role?.includes('REGULATOR') ? (
<Button
onClick={() => navigate('/projects')}
className="naxatw-cursor-pointer !naxatw-rounded-[3.125rem] naxatw-border naxatw-px-5 naxatw-py-3 naxatw-text-body-md naxatw-font-normal naxatw-text-landing-white"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Button } from '@Components/RadixComponents/Button';
import { regulatorComment } from '@Services/createproject';
import { useMutation } from '@tanstack/react-query';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
import { toast } from 'react-toastify';

const ApprovalSection = () => {
const { id } = useParams();
const [comment, setComment] = useState('');
const { mutate: commentToProject, isLoading } = useMutation<
any,
any,
any,
unknown
>({
mutationFn: regulatorComment,
onSuccess: () => {
toast.success('Responded successfully');
},
onError: (err: any) => {
toast.error(err?.response?.data?.detail || err?.message || '');
},
});

const handleApprovalStatus = (status: string) => {
commentToProject({
regulator_comment: comment,
regulator_approval_status: status,
projectId: id,
});
};

return (
<>
{' '}
<div className="naxatw-mt-6 naxatw-flex naxatw-flex-col naxatw-gap-1">
<p className="naxatw-text-[0.875rem] naxatw-font-semibold naxatw-leading-normal naxatw-tracking-[0.0175rem]">
Comment
</p>
<textarea
value={comment}
onChange={e => setComment(e.target.value)}
placeholder="Comment"
name=""
id=""
cols={4}
className="naxatw-w-full naxatw-rounded-md naxatw-border naxatw-border-gray-800 naxatw-p-1"
/>
</div>
<div className="naxatw-flex naxatw-items-start naxatw-justify-start naxatw-gap-2">
<Button
variant="outline"
onClick={() => handleApprovalStatus('REJECTED')}
className="naxatw-border-red naxatw-font-primary naxatw-text-red"
isLoading={isLoading}
disabled={isLoading}
>
Reject
</Button>
<Button
variant="ghost"
onClick={() => handleApprovalStatus('APPROVED')}
className="naxatw-bg-red naxatw-font-primary naxatw-text-white"
isLoading={isLoading}
disabled={isLoading}
>
Accept
</Button>
</div>{' '}
</>
);
};

export default ApprovalSection;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button } from '@Components/RadixComponents/Button';
import ApprovalSection from './ApprovalSection';

const DescriptionSection = ({
projectData,
Expand All @@ -14,54 +14,47 @@ const DescriptionSection = ({
<p>{projectData?.description || ''}</p>
<div className="naxatw-flex naxatw-flex-col naxatw-gap-1">
<div className="naxatw-flex naxatw-gap-2">
<p className="naxatw-w-28">Total Project Area </p>
<p className="naxatw-w-[118px]">Total Project Area </p>
<p>:</p>
<p className="naxatw-font-semibold">
{projectData?.project_area || ''}
{projectData?.project_area?.toFixed(3)?.replace(/\.00$/, '') ||
''}{' '}
km²
</p>
</div>
<div className="naxatw-flex naxatw-gap-2">
<p className="naxatw-w-28">Project Created By </p>
<p className="naxatw-w-[118px]">Project Created By </p>
<p>:</p>{' '}
<p className="naxatw-font-semibold">
{projectData?.author_name || ''}
</p>
</div>
<div className="naxatw-flex naxatw-gap-2">
<p className="naxatw-w-28"> Total Tasks </p>
<p className="naxatw-w-[118px]"> Total Tasks </p>
<p>:</p>{' '}
<p className="naxatw-font-semibold">
{projectData?.tasks?.length || ''}
</p>
</div>
{projectData?.regulator_comment && (
<div className="naxatw-flex naxatw-gap-2">
<p className="naxatw-w-[118px]"> Regulator Comment </p>
<p>:</p>{' '}
<p className="naxatw-font-semibold">
{projectData?.regulator_comment || ''}
</p>
</div>
)}
<div className="naxatw-flex naxatw-gap-2">
<p className="naxatw-w-[118px]">Regulator Approval Status</p>
<p>:</p>{' '}
<p className="naxatw-font-semibold">
{projectData?.regulator_approval_status || ''}
</p>
</div>
</div>
</div>
<div className="naxatw-mt-6 naxatw-flex naxatw-flex-col naxatw-gap-1">
<p className="naxatw-text-[0.875rem] naxatw-font-semibold naxatw-leading-normal naxatw-tracking-[0.0175rem]">
Comment
</p>
<textarea
placeholder="Comment"
name=""
id=""
cols={4}
className="naxatw-w-full naxatw-rounded-md naxatw-border naxatw-border-gray-800 naxatw-p-1"
/>
</div>
<div className="naxatw-flex naxatw-items-start naxatw-justify-start naxatw-gap-2">
<Button
variant="outline"
className="naxatw-border-red naxatw-font-primary naxatw-text-red"
>
Reject
</Button>
<Button
variant="ghost"
className="naxatw-bg-red naxatw-font-primary naxatw-text-white"
>
Accept
</Button>
</div>
<ApprovalSection />
</div>
);
};
Expand Down
11 changes: 7 additions & 4 deletions src/frontend/src/components/RegulatorsApprovalPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import Tab from '@Components/common/Tabs';
import DescriptionSection from '@Components/RegulatorsApprovalPage/DescriptionSection';
import DescriptionSection from '@Components/RegulatorsApprovalPage/Description/DescriptionSection';
import { tabOptions } from '@Constants/approvalPage';
import { useState } from 'react';
import InstructionSection from './InstructionSection';

const getContent = (selectedTab: string, projectData: Record<string, any>) => {
const getContent = (
selectedTab: string | number,
projectData: Record<string, any>,
) => {
if (selectedTab === 'about')
return <DescriptionSection projectData={projectData} />;
return (
Expand All @@ -14,15 +17,15 @@ const getContent = (selectedTab: string, projectData: Record<string, any>) => {
);
};
const DetailsTemplate = ({ projectData }: Record<string, any>) => {
const [selectedTab, setSelectedTab] = useState('about');
const [selectedTab, setSelectedTab] = useState<string | number>('about');

return (
<div className="naxatw-w-full naxatw-max-w-[30rem]">
<Tab
orientation="row"
className="naxatw-bg-transparent hover:naxatw-border-b-2 hover:naxatw-border-red"
activeClassName="naxatw-border-b-2 naxatw-bg-transparent naxatw-border-red"
onTabChange={(val: any) => {
onTabChange={(val: string | number) => {
setSelectedTab(val);
}}
tabOptions={tabOptions}
Expand Down
68 changes: 38 additions & 30 deletions src/frontend/src/components/common/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { FlexRow } from '../Layouts';
export default function Navbar() {
const { pathname } = useLocation();
const navigate = useNavigate();
const pathnameOnArray = pathname?.split('/');
const isApprovalPage =
pathnameOnArray?.includes('projects') &&
pathnameOnArray?.includes('approval');

return (
<nav className="naxatw-h-[3.5rem] naxatw-border-b naxatw-border-grey-300 naxatw-pb-2 naxatw-pt-4">
Expand All @@ -23,36 +27,40 @@ export default function Navbar() {
className="naxatw-h-8 naxatw-w-40"
/>
</div>
<FlexRow className="naxatw-gap-4">
<NavLink
to="/projects"
className={({ isActive }) =>
`${
isActive || pathname.includes('project')
? 'naxatw-border-b-2 naxatw-border-red'
: 'hover:naxatw-border-b-2 hover:naxatw-border-grey-900'
} -naxatw-mb-[1.2rem] naxatw-px-3 naxatw-pb-2 naxatw-text-body-btn`
}
>
Projects
</NavLink>
<NavLink
to="/dashboard"
className={({ isActive }) =>
`${
isActive
? 'naxatw-border-b-2 naxatw-border-red'
: 'hover:naxatw-border-b-2 hover:naxatw-border-grey-900'
} -naxatw-mb-[1.2rem] naxatw-px-3 naxatw-pb-2 naxatw-text-body-btn`
}
>
Dashboard
</NavLink>
</FlexRow>
<FlexRow className="naxatw-items-center" gap={2}>
{/* <Icon name="notifications" /> */}
<UserProfile />
</FlexRow>
{!isApprovalPage && (
<>
<FlexRow className="naxatw-gap-4">
<NavLink
to="/projects"
className={({ isActive }) =>
`${
isActive || pathname.includes('project')
? 'naxatw-border-b-2 naxatw-border-red'
: 'hover:naxatw-border-b-2 hover:naxatw-border-grey-900'
} -naxatw-mb-[1.2rem] naxatw-px-3 naxatw-pb-2 naxatw-text-body-btn`
}
>
Projects
</NavLink>
<NavLink
to="/dashboard"
className={({ isActive }) =>
`${
isActive
? 'naxatw-border-b-2 naxatw-border-red'
: 'hover:naxatw-border-b-2 hover:naxatw-border-grey-900'
} -naxatw-mb-[1.2rem] naxatw-px-3 naxatw-pb-2 naxatw-text-body-btn`
}
>
Dashboard
</NavLink>
</FlexRow>
<FlexRow className="naxatw-items-center" gap={2}>
{/* <Icon name="notifications" /> */}
<UserProfile />
</FlexRow>
</>
)}
</FlexRow>
</nav>
);
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/routes/appRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const appRoutes: IRoute[] = [
path: 'projects/:id/approval',
name: 'Task project approval',
component: RegulatorsApprovalPage,
authenticated: true,
authenticated: false,
},
];

Expand Down
16 changes: 16 additions & 0 deletions src/frontend/src/services/createproject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,19 @@ export const postTaskBoundary = ({ id, data }: { id: number; data: any }) =>

export const getProjectCentroid = () =>
authenticated(api).get('/projects/centroids');

export const regulatorUser = (data: Record<string, any>) =>
api.post(`/users/regulator/`, data, {
headers: { 'Content-Type': 'application/json' },
});

export const regulatorComment = (payload: Record<string, any>) => {
const { projectId, ...data } = payload;
return authenticated(api).post(
`/projects/regulator/comment/${projectId}/`,
data,
{
headers: { 'Content-Type': 'application/json' },
},
);
};
Loading

0 comments on commit 32f9d91

Please sign in to comment.