-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MD-5019] Implement Global Filter Selector (#3)
* Added TRPC and global filter component/feature * Address Jack's PR comments on 10/14 * Added vercel deployment for this repo Remove unused var @/api path to @isomorphic/api since it's now a separate package Fix build errors Add env in turbo.json
- Loading branch information
1 parent
759072d
commit 4edba6c
Showing
25 changed files
with
1,279 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/// <reference types="next" /> | ||
/// <reference types="next/image-types/global" /> | ||
/// <reference types="next/navigation-types/compat/navigation" /> | ||
|
||
// NOTE: This file should not be edited | ||
// see https://nextjs.org/docs/basic-features/typescript for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 33 additions & 28 deletions
61
apps/isomorphic-i18n/src/app/api/aggregated-catch/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,53 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import clientPromise from '@/app/mongodb'; | ||
import { NextRequest, NextResponse } from "next/server"; | ||
import clientPromise from "@/app/mongodb"; | ||
|
||
export async function GET(req: NextRequest) { | ||
try { | ||
const client = await clientPromise; | ||
const db = client.db('kenya'); | ||
const collection = db.collection('legacy_data'); | ||
|
||
// Filter and aggregate data | ||
const data = await collection.aggregate([ | ||
try { | ||
const client = await clientPromise; | ||
const db = client.db("kenya"); | ||
const collection = db.collection("legacy_data"); | ||
|
||
// Filter and aggregate data | ||
const data = await collection | ||
.aggregate([ | ||
{ | ||
$match: { | ||
landing_site: "Kenyatta" | ||
} | ||
landing_site: "Kenyatta", | ||
}, | ||
}, | ||
{ | ||
$project: { | ||
landing_date: { | ||
$dateTrunc: { | ||
date: "$landing_date", | ||
unit: "month" | ||
} | ||
unit: "month", | ||
}, | ||
}, | ||
fish_category: 1, | ||
catch_kg: 1 | ||
} | ||
catch_kg: 1, | ||
}, | ||
}, | ||
{ | ||
$group: { | ||
_id: { | ||
landing_date: "$landing_date", | ||
fish_category: "$fish_category" | ||
fish_category: "$fish_category", | ||
}, | ||
catch_kg: { $sum: "$catch_kg" } | ||
} | ||
catch_kg: { $sum: "$catch_kg" }, | ||
}, | ||
}, | ||
{ | ||
$sort: { "_id.landing_date": 1, "_id.fish_category": 1 } | ||
} | ||
]).toArray(); | ||
|
||
return NextResponse.json(data); | ||
} catch (error) { | ||
console.error('Error fetching data:', (error as Error).message); | ||
return NextResponse.json({ error: 'Internal Server Error', details: (error as Error).message }, { status: 500 }); | ||
} | ||
} | ||
$sort: { "_id.landing_date": 1, "_id.fish_category": 1 }, | ||
}, | ||
]) | ||
.toArray(); | ||
|
||
return NextResponse.json(data); | ||
} catch (error) { | ||
console.error("Error fetching data:", (error as Error).message); | ||
return NextResponse.json( | ||
{ error: "Internal Server Error", details: (error as Error).message }, | ||
{ status: 500 } | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { appRouter, createTRPCContext } from "@isomorphic/api"; | ||
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; | ||
|
||
/** | ||
* Configure basic CORS headers | ||
* You should extend this to match your needs | ||
*/ | ||
function setCorsHeaders(res: Response) { | ||
res.headers.set("Access-Control-Allow-Origin", "*"); | ||
res.headers.set("Access-Control-Request-Method", "*"); | ||
res.headers.set("Access-Control-Allow-Methods", "OPTIONS, GET, POST"); | ||
res.headers.set("Access-Control-Allow-Headers", "*"); | ||
} | ||
|
||
export function OPTIONS() { | ||
const response = new Response(null, { | ||
status: 204, | ||
}); | ||
setCorsHeaders(response); | ||
return response; | ||
} | ||
|
||
const handler = async (req: any) => { | ||
const response = await fetchRequestHandler({ | ||
endpoint: "/api/trpc", | ||
router: appRouter, | ||
req, | ||
createContext: () => { | ||
return createTRPCContext({ | ||
session: req.auth, | ||
headers: req.headers, | ||
}); | ||
}, | ||
onError({ error, path }) { | ||
console.error(`>>> tRPC Error on '${path}'`, error); | ||
}, | ||
}); | ||
|
||
setCorsHeaders(response); | ||
return response; | ||
}; | ||
|
||
export { handler as GET, handler as POST }; |
140 changes: 140 additions & 0 deletions
140
apps/isomorphic-i18n/src/app/components/filter-selector.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { ActionIcon, Checkbox, Input, Popover } from "rizzui"; | ||
import { TbFilterCog } from "react-icons/tb"; | ||
import { ChangeEvent, useEffect, useMemo, useState } from "react"; | ||
import { BmuType, useGlobalFilter } from "./global-filter-provider"; | ||
import Fuse from "fuse.js"; | ||
|
||
export const FilterSelector = () => { | ||
const [searchFilter, setSearchFilter] = useState(""); | ||
const [filteredList, setFilteredList] = useState<BmuType[] | string[]>([]); | ||
const [isOpen, setIsOpen] = useState(false); | ||
const { bmuOriginalData, bmuFilter, setBmuFilter } = useGlobalFilter(); | ||
|
||
const fuse = new Fuse( | ||
bmuOriginalData.flatMap((section) => | ||
section.units.map((unit) => unit.value) | ||
), | ||
{ | ||
includeScore: true, | ||
} | ||
); | ||
|
||
useEffect(() => { | ||
setFilteredList(bmuOriginalData); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => { | ||
setSearchFilter(e.target.value); | ||
if (e.target.value) { | ||
const result = fuse.search(e.target.value); | ||
setFilteredList(result.map((res) => res.item)); | ||
} else { | ||
setFilteredList(bmuOriginalData); | ||
} | ||
}; | ||
|
||
return ( | ||
<Popover isOpen={isOpen} setIsOpen={setIsOpen} placement="bottom-end"> | ||
<Popover.Trigger> | ||
<ActionIcon variant="text" className="relative"> | ||
<TbFilterCog className="h-6 w-6 fill-[#D6D6D6] [stroke-width:1.5px]" /> | ||
</ActionIcon> | ||
</Popover.Trigger> | ||
<Popover.Content className="w-[350px]"> | ||
<Input | ||
placeholder="Search here..." | ||
value={searchFilter} | ||
onChange={handleSearchChange} | ||
/> | ||
<div className="space-y-2 mt-4"> | ||
{filteredList.map((section, idx) => { | ||
return ( | ||
<FilterGroup | ||
key={`bmu-section-${idx}`} | ||
bmuSection={section} | ||
searchFilter={searchFilter} | ||
/> | ||
); | ||
})} | ||
</div> | ||
</Popover.Content> | ||
</Popover> | ||
); | ||
}; | ||
|
||
const FilterGroup = ({ | ||
bmuSection, | ||
searchFilter, | ||
}: { | ||
bmuSection: BmuType | string; | ||
searchFilter: string; | ||
}) => { | ||
const { bmuFilter, setBmuFilter } = useGlobalFilter(); | ||
|
||
const handleBmuSelect = (unit: string) => { | ||
if (bmuFilter.includes(unit)) { | ||
setBmuFilter(bmuFilter.filter((filter) => filter !== unit)); | ||
} else { | ||
setBmuFilter([...bmuFilter, unit]); | ||
} | ||
}; | ||
|
||
if (typeof bmuSection === "string" && searchFilter) { | ||
const unit = bmuSection as string; | ||
|
||
return ( | ||
<Checkbox | ||
key={unit} | ||
label={unit} | ||
checked={bmuFilter.findIndex((filter) => filter === unit) !== -1} | ||
onChange={() => handleBmuSelect(unit)} | ||
/> | ||
); | ||
} else { | ||
const section = bmuSection as BmuType; | ||
const allSelected = section.units.every((unit) => { | ||
return bmuFilter.includes(unit.value); | ||
}); | ||
|
||
const handleSectionSelect = () => { | ||
if (allSelected) { | ||
setBmuFilter( | ||
bmuFilter.filter( | ||
(filter) => | ||
!section.units.flatMap((unit) => unit.value).includes(filter) | ||
) | ||
); | ||
} else { | ||
setBmuFilter([ | ||
...bmuFilter, | ||
...section.units.map((unit) => unit.value), | ||
]); | ||
} | ||
}; | ||
|
||
return ( | ||
<div> | ||
<Checkbox | ||
label={section.sectionName} | ||
checked={allSelected} | ||
onChange={handleSectionSelect} | ||
/> | ||
<div className="mt-2 ml-8 space-y-2"> | ||
{section.units.map((unit) => { | ||
return ( | ||
<Checkbox | ||
key={unit.value} | ||
label={unit.value} | ||
checked={ | ||
bmuFilter.findIndex((filter) => filter === unit.value) !== -1 | ||
} | ||
onChange={() => handleBmuSelect(unit.value)} | ||
/> | ||
); | ||
})} | ||
</div> | ||
</div> | ||
); | ||
} | ||
}; |
Oops, something went wrong.