added grouping creator
All checks were successful
backend-action / build-image (push) Successful in 1m5s

This commit is contained in:
2024-05-16 14:49:42 +07:00
parent 05f3e019a8
commit d125687536
5 changed files with 170 additions and 20 deletions

View File

@@ -0,0 +1,73 @@
"use client";
import { LocationContext } from "@/components/locationContenxt";
import { useContext, useEffect, useState } from "react";
import Grouping from "./Grouping";
import { unique } from "drizzle-orm/mysql-core";
type Props = {
allJobs: JobCategory[];
};
export type JobCategory = {
id: number;
name: string;
};
type Group = {
id: number;
jobs: number[];
};
export default function GroupCreator({ allJobs }: Props) {
let locationContext = useContext(LocationContext);
let [usedJobs, setUsedJobs] = useState<number[]>([]);
let [groups, setGroup] = useState<Group[]>(
[...Array(4).keys()].map((i) => ({ id: i + 1, jobs: [] }))
);
function useJob(id: number) {
setUsedJobs((u) => [...u, id]);
}
function freeJob(id: number) {
setUsedJobs((u) => u.filter((j) => j != id));
}
function updateGroup(id: number, jobs: number[]) {
setGroup((groups) =>
groups.map((g) => {
if (g.id != id) return g;
else return { id, jobs };
})
);
}
useEffect(() => {
console.log(groups);
}, [groups]);
if (
locationContext?.zone[0] == undefined ||
locationContext?.province[0] == undefined
) {
return undefined;
}
return (
<div>
{groups.map((g) => (
<div className="flex flex-col items-center" key={g.id}>
<p>: {g.id}</p>
<Grouping
availableJobs={allJobs.filter((j) => !usedJobs.includes(j.id))}
selectJob={useJob}
removeJob={freeJob}
updateGroup={(ids) => updateGroup(g.id, ids)}
/>
</div>
))}
<div className="flex justify-center">
<button className="bg-green-300 rounded-md p-2"></button>
</div>
</div>
);
}

59
app/grouping/Grouping.tsx Normal file
View File

@@ -0,0 +1,59 @@
import { useEffect, useState } from "react";
import { JobCategory } from "./GroupCreator";
type Props = {
availableJobs: JobCategory[];
selectJob: (id: number) => void;
removeJob: (id: number) => void;
updateGroup: (id: number[]) => void;
};
export default function Grouping({
availableJobs,
selectJob,
removeJob,
updateGroup,
}: Props) {
let [selectedJob, setSelectedJob] = useState<JobCategory[]>([]);
function addJob(id: string) {
let _id = parseInt(id);
let job = availableJobs.find((j) => j.id == _id);
if (job == undefined) return;
setSelectedJob((old) => [...old, job]);
selectJob(_id);
}
function removeJobFromGroup(id: number) {
setSelectedJob((old) => old.filter((j) => j.id != id));
removeJob(id);
}
useEffect(() => {
updateGroup(selectedJob.map((j) => j.id));
}, [selectedJob]);
return (
<div className="flex flex-col gap-2 m-2 p-2 border-black rounded-md shadow-md border w-full">
{selectedJob.map((j) => (
<div className="flex justify-between gap-2 p-2" key={j.id}>
<p>{j.name}</p>
<button
onClick={() => removeJobFromGroup(j.id)}
className="text-red-400"
>
</button>
</div>
))}
{selectedJob.length < 5 && (
<select onChange={(e) => addJob(e.currentTarget.value)}>
<option value={undefined} hidden>
None
</option>
{availableJobs.map((j) => (
<option value={j.id} key={j.id}>
{j.name}
</option>
))}
</select>
)}
</div>
);
}

View File

@@ -1,14 +1,17 @@
import { db } from "@/src/db"; import { db } from "@/src/db";
import LocationSelector from "../../components/LocationSelector"; import LocationSelector from "../../components/LocationSelector";
import LocationContextProvider from "@/components/locationContenxt"; import LocationContextProvider from "@/components/locationContenxt";
import GroupCreator from "./GroupCreator";
export default async function Page() { export default async function Page() {
let provinces = await db.query.province let provinces = await db.query.province
.findMany({ with: { zones: true } }) .findMany({ with: { zones: true } })
.execute(); .execute();
let jobList = await db.query.group.findMany().execute();
return ( return (
<LocationContextProvider> <LocationContextProvider>
<LocationSelector provinces={provinces} /> <LocationSelector provinces={provinces} />
<GroupCreator allJobs={jobList} />
</LocationContextProvider> </LocationContextProvider>
); );
} }

View File

@@ -6,8 +6,11 @@ export default function RootLayout({
}) { }) {
return ( return (
<html lang="en"> <html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body> <body>
<div className="container mx-auto mt-2">{children}</div> <div className="container mx-auto mt-2 p-2">{children}</div>
</body> </body>
</html> </html>
); );

View File

@@ -46,30 +46,42 @@ export default function LocationSelector({ provinces }: Props) {
}, [amphurId]); }, [amphurId]);
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<select <div className="flex gap-2">
value={provinceId} :
onChange={(e) => setProvince(e.currentTarget.value)}
>
<option value={undefined}>None</option>
{provinces.map((p) => (
<option key={p.id} value={p.id}>
{p.name}
</option>
))}
</select>
{amphurList && (
<select <select
value={amphurId} value={provinceId}
onChange={(e) => setAmphur(e.currentTarget.value)} className="flex-1"
onChange={(e) => setProvince(e.currentTarget.value)}
> >
<option value={undefined}>None</option> <option value={undefined} hidden>
{amphurList.map((a) => ( None
<option key={a.id} value={a.id}> </option>
{a.name} {provinces.map((p) => (
<option key={p.id} value={p.id}>
{p.name}
</option> </option>
))} ))}
</select> </select>
</div>
{amphurList && (
<div className="flex gap-2">
:
<select
value={amphurId}
className="flex-1"
onChange={(e) => setAmphur(e.currentTarget.value)}
>
<option value={undefined} hidden>
None
</option>
{amphurList.map((a) => (
<option key={a.id} value={a.id}>
{a.name}
</option>
))}
</select>
</div>
)} )}
</div> </div>
); );