Skip to content

Commit a31fde2

Browse files
authored
Merge pull request #186 from CivicDataLab/173-add-usecases-creation-flow
173 add UseCase creation flow under manage
2 parents 4e59046 + 626db9c commit a31fde2

File tree

10 files changed

+1062
-9
lines changed

10 files changed

+1062
-9
lines changed

app/[locale]/dashboard/[entityType]/[entitySlug]/dataset/[id]/edit/charts/components/ChartsVisualize.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ const ChartsVisualize: React.FC<VisualizationProps> = ({
185185
name: '',
186186
description: '',
187187
chartType: 'BAR_VERTICAL',
188-
resource: data?.datasetResources[0].id,
188+
resource: data?.datasetResources[0]?.id,
189189
xAxisColumn: '',
190190
xAxisLabel: '',
191191
yAxisColumn: '',
@@ -205,7 +205,7 @@ const ChartsVisualize: React.FC<VisualizationProps> = ({
205205
if (data) {
206206
if (!chartId && data?.datasetResources.length) {
207207
// Set initial resource schema and chart data
208-
const initialResource = data.datasetResources[0];
208+
const initialResource = data?.datasetResources[0];
209209
setResourceSchema(initialResource.schema || []);
210210
setChartData((prevData) => ({
211211
...prevData,
@@ -297,7 +297,7 @@ const ChartsVisualize: React.FC<VisualizationProps> = ({
297297
showLegend: updatedData.showLegend,
298298
xAxisLabel: updatedData.xAxisLabel,
299299
yAxisLabel: updatedData.yAxisLabel,
300-
resource: updatedData.resource || data?.datasetResources[0].id,
300+
resource: updatedData.resource || data?.datasetResources[0]?.id,
301301
xAxisColumn: updatedData.xAxisColumn,
302302
yAxisColumn: updatedData.yAxisColumn,
303303
regionColumn: updatedData.regionColumn,
@@ -446,7 +446,7 @@ const ChartsVisualize: React.FC<VisualizationProps> = ({
446446
value: resource.id,
447447
}))}
448448
value={chartData.resource}
449-
defaultValue={data?.datasetResources[0].id}
449+
defaultValue={data?.datasetResources[0]?.id}
450450
label="Select Resources"
451451
onBlur={() => handleSave(chartData)}
452452
onChange={(e) => handleResourceChange(e)}

app/[locale]/manage/layout.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import { useParams } from 'next/navigation';
5+
import { SidebarNavItem } from '@/types';
6+
7+
import { cn } from '@/lib/utils';
8+
import BreadCrumbs from '@/components/BreadCrumbs';
9+
import { DashboardNav } from '../dashboard/components/dashboard-nav';
10+
import { MobileDashboardNav } from '../dashboard/components/mobile-dashboard-nav';
11+
import styles from '../dashboard/components/styles.module.scss';
12+
import LoadingPage from '../dashboard/loading';
13+
14+
interface DashboardLayoutProps {
15+
children?: React.ReactNode;
16+
}
17+
18+
export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
19+
const [isOpened, setIsOpened] = React.useState(false);
20+
21+
const params = useParams<{ organizationId: string }>();
22+
23+
const orgSidebarNav: Array<SidebarNavItem> = [
24+
{
25+
title: 'Use Cases',
26+
href: `/manage/usecases`,
27+
icon: 'datasetEdit',
28+
},
29+
];
30+
31+
const organizationId = params.organizationId;
32+
33+
return (
34+
<React.Suspense fallback={<LoadingPage />}>
35+
<BreadCrumbs
36+
data={[
37+
{ href: '/', label: 'Home' },
38+
{
39+
href: '',
40+
label: 'Manage',
41+
},
42+
]}
43+
/>
44+
<div
45+
className={cn(
46+
'relative flex flex-col md:flex-row',
47+
' bg-surfaceDefault p-4 md:flex'
48+
)}
49+
>
50+
<DashboardNav items={orgSidebarNav} entitySlug={organizationId} />
51+
52+
<div className="z-1 basis-2 md:hidden">
53+
<MobileDashboardNav
54+
setIsOpened={setIsOpened}
55+
isOpened={isOpened}
56+
items={orgSidebarNav}
57+
/>
58+
</div>
59+
<div className={cn(styles.Main)}>{children}</div>
60+
</div>
61+
</React.Suspense>
62+
);
63+
}

app/[locale]/manage/page.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use client';
2+
3+
import { useRouter } from 'next/navigation';
4+
import { useEffect } from 'react';
5+
6+
import { Loading } from '@/components/loading';
7+
8+
const Manage = () => {
9+
const router = useRouter();
10+
useEffect(() => {
11+
// Redirect to the Use Cases page
12+
router.push(`/manage/usecases`);
13+
}, [router]);
14+
return (
15+
<div>
16+
<Loading />
17+
</div> // Optional: You can show a loading message or spinner here
18+
);
19+
};
20+
export default Manage;
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
'use client';
2+
3+
import React, { useEffect, useState } from 'react';
4+
import { useParams, useRouter } from 'next/navigation';
5+
import { fetchDatasets } from '@/fetch';
6+
import { graphql } from '@/gql';
7+
import { useMutation, useQuery } from '@tanstack/react-query';
8+
import { Button, DataTable, Text, toast } from 'opub-ui';
9+
10+
import { GraphQL } from '@/lib/api';
11+
import { formatDate } from '@/lib/utils';
12+
import { Loading } from '@/components/loading';
13+
14+
const FetchUseCaseDetails: any = graphql(`
15+
query UseCaseDetails($filters: UseCaseFilter) {
16+
useCases(filters: $filters) {
17+
id
18+
title
19+
datasets {
20+
id
21+
title
22+
modified
23+
categories {
24+
name
25+
}
26+
}
27+
}
28+
}
29+
`);
30+
31+
const AssignUsecaseDatasets: any = graphql(`
32+
mutation assignDatasets($useCaseId: Int!, $datasetIds: [UUID!]!) {
33+
updateUsecaseDatasets(useCaseId: $useCaseId, datasetIds: $datasetIds) {
34+
... on TypeUseCase {
35+
id
36+
datasets {
37+
id
38+
title
39+
}
40+
}
41+
}
42+
}
43+
`);
44+
const Assign = () => {
45+
const params = useParams();
46+
const router = useRouter();
47+
48+
const [data, setData] = useState<any[]>([]); // Ensure `data` is an array
49+
const [selectedRow, setSelectedRows] = useState<any[]>([]);
50+
51+
const UseCaseDetails: { data: any; isLoading: boolean; refetch: any } =
52+
useQuery(
53+
[`UseCase_Details`, params.id],
54+
() =>
55+
GraphQL(
56+
FetchUseCaseDetails,
57+
{},
58+
{
59+
filters: {
60+
id: params.id,
61+
},
62+
}
63+
),
64+
{
65+
refetchOnMount: true,
66+
refetchOnReconnect: true,
67+
}
68+
);
69+
70+
const formattedData = (data: any) =>
71+
data.map((item: any) => {
72+
return {
73+
title: item.title,
74+
id: item.id,
75+
category: item.categories[0]?.name || 'N/A', // Safeguard in case of missing category
76+
modified: formatDate(item.modified),
77+
};
78+
});
79+
80+
useEffect(() => {
81+
fetchDatasets('?size=1000&page=1')
82+
.then((res) => {
83+
setData(res.results);
84+
})
85+
.catch((err) => {
86+
console.error(err);
87+
});
88+
}, []);
89+
90+
91+
92+
const columns = [
93+
{ accessorKey: 'title', header: 'Title' },
94+
{ accessorKey: 'category', header: 'Category' },
95+
{ accessorKey: 'modified', header: 'Last Modified' },
96+
];
97+
98+
99+
const generateTableData = (list: Array<any>) => {
100+
return list.map((item) => {
101+
return {
102+
title: item.title,
103+
id: item.id,
104+
category: item.categories[0],
105+
modified: formatDate(item.modified),
106+
};
107+
});
108+
};
109+
110+
const { mutate, isLoading: mutationLoading } = useMutation(
111+
() =>
112+
GraphQL(
113+
AssignUsecaseDatasets,
114+
{},
115+
{
116+
useCaseId: +params.id,
117+
datasetIds: Array.isArray(selectedRow)
118+
? selectedRow.map((row: any) => row.id)
119+
: [],
120+
}
121+
),
122+
{
123+
onSuccess: (data: any) => {
124+
toast('Dataset Assigned Successfully');
125+
UseCaseDetails.refetch();
126+
router.push(`/manage/usecases/edit/${params.id}/publish`);
127+
},
128+
onError: (err: any) => {
129+
toast(`Received ${err} on dataset publish `);
130+
},
131+
}
132+
);
133+
134+
return (
135+
<>
136+
{UseCaseDetails?.data?.useCases[0]?.datasets?.length >= 0 &&
137+
data.length > 0 &&
138+
!UseCaseDetails.isLoading ? (
139+
<>
140+
<div className="flex justify-between">
141+
<div>
142+
<Text>
143+
Selected {selectedRow.length} of {data.length}
144+
</Text>
145+
</div>
146+
<div className="mb-4 flex justify-end">
147+
<Button className="w-fit" onClick={() => mutate()}>
148+
Submit
149+
</Button>
150+
</div>
151+
</div>
152+
153+
<DataTable
154+
columns={columns}
155+
rows={generateTableData(data)}
156+
defaultSelectedRows={formattedData(
157+
UseCaseDetails?.data?.useCases[0]?.datasets
158+
)}
159+
onRowSelectionChange={(selected) => {
160+
setSelectedRows(Array.isArray(selected) ? selected : []); // Ensure selected is always an array
161+
}}
162+
/>
163+
</>
164+
) : (
165+
<Loading />
166+
)}
167+
</>
168+
);
169+
};
170+
171+
export default Assign;

0 commit comments

Comments
 (0)