Skip to content

Commit

Permalink
Merge pull request #273 from CivicDataLab/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
PixeledCode authored Dec 1, 2023
2 parents 35a86f5 + e7704e8 commit ade3b5e
Show file tree
Hide file tree
Showing 35 changed files with 547 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ import { useFetch } from '@/lib/api';
import { cn, copyURLToClipboard, exportAsImage } from '@/lib/utils';
import {
Button,
Combobox,
ComboboxMulti,
Select,
SelectorCard,
Tab,
TabList,
TabPanel,
Tabs,
Text,
Tray,
useToast,
} from 'opub-ui';
import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useQueryState } from 'next-usequerystate';
import dynamic from 'next/dynamic';
import { BarView } from './BarView';
import { useWindowSize } from '@/hooks/use-window-size';

const LeafletChoropleth = dynamic(
() => import('opub-viz').then((mod) => mod.LeafletChoropleth),
Expand All @@ -42,6 +44,8 @@ export const Explorer = React.forwardRef(
const [selectedYear, setYear] = React.useState(Object.keys(years)[0]);
const [selectedTab, setTab] = React.useState<'map' | 'bar'>('bar');
const [indicator, setIndicator] = useQueryState('indicator');
const [indicatorName, setIndicatorName] = React.useState('indicator');
const [trayOpen, setTrayOpen] = React.useState(false);

const { data: indicatorData, isLoading } = useFetch(
'indicators',
Expand All @@ -58,10 +62,28 @@ export const Explorer = React.forwardRef(
}
}, [indicatorData, indicator]);

// TODO: improve this section by adding better API
// set indicator name
React.useEffect(() => {
if (indicatorData) {
const indicatorObjsArr: any = Object.values(
indicatorData[scheme as string]
);
indicatorObjsArr.forEach((objsArr: any) => {
const indicatorObj = objsArr.find((e: any) => e.slug === indicator);

if (indicatorObj) {
setIndicatorName(indicatorObj.label);
return;
}
});
}
}, [indicatorData, indicator]);

return (
<div
className={cn(
'md:grid grid-cols-[242px_1fr] gap-4 rounded-05 md:bg-surfaceDefault md:shadow-elementCard md:p-6'
'flex flex-col md:grid grid-cols-[242px_1fr] gap-4 rounded-05 md:bg-surfaceDefault md:shadow-elementCard md:p-6'
)}
>
<div className="hidden md:block">
Expand All @@ -82,27 +104,35 @@ export const Explorer = React.forwardRef(
</div>
)}
</div>
{/* <div className="md:hidden">
<Select
label="Select Indicator"
labelHidden
name="indicator"
onChange={(value) => {
setIndicator(value);
}}
value={indicator}
options={
indicatorData
? indicatorData[scheme as string]['District Performance'].map(
(e: any) => ({
label: e.label,
value: e.slug,
})
)
: []
}
<div className="block md:hidden">
<SelectorCard
title="Selected Indicator"
selected={indicatorName}
buttonText="Switch Indicator"
onClick={() => setTrayOpen(true)}
/>
</div> */}
<Tray open={trayOpen} onOpenChange={setTrayOpen} size="extended">
{isLoading ? (
<div className="p-4">
<Text variant="headingMd">Loading...</Text>
</div>
) : indicatorData ? (
<Indicators
data={indicatorData[scheme as string] || null}
indicator={indicator || 'nhaoe'}
indicatorRef={indicatorRef}
setIndicator={(e: string) => {
setIndicator(e);
setTrayOpen(false);
}}
/>
) : (
<div className="p-4">
<Text variant="headingMd">No indicators available</Text>
</div>
)}
</Tray>
</div>

<div className="flex items-center justify-center h-full" ref={ref}>
<ErrorBoundary
Expand Down Expand Up @@ -255,23 +285,24 @@ const Content = ({
mapDataFn={mapDataFn}
fillOpacity={1}
className="w-full h-[512px]"
// mouseover={handleMouseOver}
// mouseout={handleMouseOut}
/>
) : (
<div className="flex justify-center items-center">Loading...</div>
),
},
];

const { width } = useWindowSize();
const isMobile = width ? width < 768 : false;

return (
<div className="grow h-full">
<Tabs
defaultValue={'map'}
onValueChange={(value) => states.setTab(value as any)}
value={states.selectedTab}
>
<TabList>
<TabList fitted={isMobile}>
{[
{
label: 'Bar View',
Expand All @@ -298,6 +329,7 @@ const Content = ({
setSelectedBlocks={setSelectedBlocks}
tab={states.selectedTab}
selectedBlocks={selectedBlocks}
isMobile={isMobile}
/>

{tabs.map((tab) => (
Expand Down Expand Up @@ -343,13 +375,15 @@ const Filters = ({
setSelectedBlocks,
tab,
selectedBlocks,
isMobile,
}: {
states: any;
chartData: IChartData;
barOptions: any;
setSelectedBlocks: any;
tab: 'map' | 'bar';
selectedBlocks: string[];
isMobile: boolean;
}) => {
const options = Object.keys(Object.values(chartData)[0].years).map(
(year) => ({
Expand All @@ -359,7 +393,7 @@ const Filters = ({
);

return (
<div className="flex flex-col gap-4 px-4">
<div className="flex flex-col gap-2 md:gap-4 px-4">
{tab === 'bar' && (
<ComboboxMulti
name="blocks"
Expand All @@ -383,6 +417,7 @@ const Filters = ({
onChange={states.setYear}
value={states.selectedYear}
options={options}
className="w-full md:w-fit"
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { indicatorFilter } from '../scheme.config';
import Icons from '@/components/icons';
import {
Icon,
Input,
RadioGroup,
RadioItem,
ScrollArea,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,6 @@ export const IndicatorsCheckbox = ({
const [search, setSearch] = React.useState('');
const [filtered, setFiltered] = React.useState<any>(data ? data : null);

React.useEffect(() => {
// set first 5 District Performance indicators as selected by default
const firstFive = data['District Performance'].slice(0, 5);
setIndicators((prev: any) => {
return {
...prev,
'District Performance': firstFive.map((item: any) => item.value),
};
});
}, []);

React.useEffect(() => {
// filter indicators based on search
if (search === '') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ const Card = ({
children: React.ReactNode;
}) => {
return (
<section className="p-6 bg-surfaceDefault rounded-2 shadow-basicMd">
<section className="p-3 md:p-6 bg-surfaceDefault rounded-2 shadow-basicMd">
<Text variant="headingXl" as="h3">
{heading}
</Text>
<div className="mt-6 flex flex-wrap gap-4">
<div className="mt-4 md:mt-6 flex flex-wrap gap-2 md:gap-4">
<>{children}</>
</div>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ import { ckan } from '@/config/site';
import { useFetch } from '@/lib/api';
import { cn, copyURLToClipboard } from '@/lib/utils';
import { createColumnHelper } from '@tanstack/react-table';
import { useToast } from 'opub-ui';
import { Button, Select, Table, Text } from 'opub-ui';
import {
Button,
Select,
Table,
Text,
Tray,
Pill,
SelectorCard,
useToast,
} from 'opub-ui';
import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';

Expand All @@ -18,11 +26,12 @@ export const SourceData = ({
scheme?: string;
}) => {
const [selectedYear, setYear] = React.useState(Object.keys(tableData)[0]);
const [selectedIndicators, setIndicators] = React.useState({
const [selectedIndicators, setSelectedIndicators] = React.useState<any>({
'District Performance': [],
'District Profile': [],
Targets: [],
});
const [trayOpen, setTrayOpen] = React.useState(false);

const { data: indicatorData, isLoading } = useFetch(
'indicators',
Expand Down Expand Up @@ -71,6 +80,20 @@ export const SourceData = ({
return data;
}, [indicatorData]);

React.useEffect(() => {
// set first 5 District Performance indicators as selected by default
const firstFive = indicatorDataWithValues['District Performance'].slice(
0,
5
);
setSelectedIndicators((prev: any) => {
return {
...prev,
'District Performance': firstFive.map((item: any) => item.value),
};
});
}, [indicatorDataWithValues]);

const columns: any = [
{
header: 'Block',
Expand All @@ -90,11 +113,75 @@ export const SourceData = ({

const { toast } = useToast();

function removePill(str: string) {
let key: string, index: number;
// find the key (indicator category) and index of the pill
Object.keys(selectedIndicators).forEach((k: any) => {
const i = selectedIndicators[k].indexOf(str);
if (i !== -1) {
key = k;
index = i;
}
});

// remove the pill
setSelectedIndicators((prev: any) => {
const data = { ...prev };
data[key].splice(index, 1);
return data;
});
}

return (
<div>
<div className="block md:hidden mb-4">
<SelectorCard
title="Selected Indicators"
selected={
<>
{allSelectedIndicators.length > 0 ? (
<div className="flex flex-col gap-1">
{allSelectedIndicators.map((item: any) => (
<Pill
variant="info"
truncate
onRemove={removePill}
returnValue={item}
>
{item}
</Pill>
))}
</div>
) : (
<Text variant="bodyMd">No indicator selected</Text>
)}
</>
}
buttonText="Edit Indicators"
onClick={() => setTrayOpen(true)}
/>
<Tray open={trayOpen} onOpenChange={setTrayOpen} size="extended">
{isLoading ? (
<div className="p-4">
<Text variant="headingMd">Loading...</Text>
</div>
) : indicatorData ? (
<IndicatorsCheckbox
data={indicatorDataWithValues}
indicatorRef={indicatorRef}
selectedIndicators={selectedIndicators}
setIndicators={setSelectedIndicators}
/>
) : (
<div className="p-4">
<Text variant="headingMd">No indicators available</Text>
</div>
)}
</Tray>
</div>
<div
className={cn(
'md:grid grid-cols-[242px_1fr] gap-4 rounded-05 bg-surfaceDefault shadow-elementCard p-6'
'md:grid grid-cols-[242px_1fr] gap-4 p-3 md:p-5 rounded-05 bg-surfaceDefault shadow-elementCard'
)}
>
<div className="hidden md:block">
Expand All @@ -107,7 +194,7 @@ export const SourceData = ({
data={indicatorDataWithValues}
indicatorRef={indicatorRef}
selectedIndicators={selectedIndicators}
setIndicators={setIndicators}
setIndicators={setSelectedIndicators}
/>
) : (
<div className="p-4">
Expand All @@ -129,14 +216,15 @@ export const SourceData = ({
<div className="flex mb-4">
<Select
name="year"
label="Year"
labelHidden
label="Select FY"
labelInline
onChange={setYear}
value={selectedYear}
options={Object.keys(tableData).map((year) => ({
label: year,
value: year,
}))}
className="w-full md:w-fit"
/>
</div>
<Table
Expand Down
Loading

1 comment on commit ade3b5e

@vercel
Copy link

@vercel vercel bot commented on ade3b5e Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

opub-www – ./apps/www

opub-www-civicdatalab.vercel.app
opub-www.vercel.app
opub-www-git-main-civicdatalab.vercel.app

Please sign in to comment.