Connect create item to backend and add associated frontend routes

This commit is contained in:
pmoharana-cmd 2025-01-04 23:26:33 -05:00
parent 49f0c4373b
commit 6d89ba6324
12 changed files with 148 additions and 41 deletions

View File

@ -19,7 +19,10 @@ openapi_tags = {
# TODO: Create custom exceptions # TODO: Create custom exceptions
@api.post("", response_model=Resource, tags=["Resource"]) @api.post("", response_model=Resource, tags=["Resource"])
def create( def create(
uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() uuid: str,
resource: Resource,
user_svc: UserService = Depends(),
resource_svc: ResourceService = Depends(),
): ):
subject = user_svc.get_user_by_uuid(uuid) subject = user_svc.get_user_by_uuid(uuid)
return resource_svc.create(subject, resource) return resource_svc.create(subject, resource)
@ -27,14 +30,20 @@ def create(
@api.get("", response_model=List[Resource], tags=["Resource"]) @api.get("", response_model=List[Resource], tags=["Resource"])
def get_all( def get_all(
uuid: str, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() uuid: str,
user_svc: UserService = Depends(),
resource_svc: ResourceService = Depends(),
): ):
subject = user_svc.get_user_by_uuid(uuid) subject = user_svc.get_user_by_uuid(uuid)
return resource_svc.get_resource_by_user(subject) return resource_svc.get_resource_by_user(subject)
@api.get("/{name}", response_model=Resource, tags=["Resource"]) @api.get("/{name}", response_model=Resource, tags=["Resource"])
def get_by_name( def get_by_name(
name:str, uuid:str, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() name: str,
uuid: str,
user_svc: UserService = Depends(),
resource_svc: ResourceService = Depends(),
): ):
subject = user_svc.get_user_by_uuid(uuid) subject = user_svc.get_user_by_uuid(uuid)
return resource_svc.get_resource_by_name(name, subject) return resource_svc.get_resource_by_name(name, subject)
@ -42,7 +51,10 @@ def get_by_name(
@api.put("", response_model=Resource, tags=["Resource"]) @api.put("", response_model=Resource, tags=["Resource"])
def update( def update(
uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() uuid: str,
resource: Resource,
user_svc: UserService = Depends(),
resource_svc: ResourceService = Depends(),
): ):
subject = user_svc.get_user_by_uuid(uuid) subject = user_svc.get_user_by_uuid(uuid)
return resource_svc.update(subject, resource) return resource_svc.update(subject, resource)
@ -50,7 +62,10 @@ def update(
@api.delete("", response_model=None, tags=["Resource"]) @api.delete("", response_model=None, tags=["Resource"])
def delete( def delete(
uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() uuid: str,
resource: Resource,
user_svc: UserService = Depends(),
resource_svc: ResourceService = Depends(),
): ):
subject = user_svc.get_user_by_uuid(uuid) subject = user_svc.get_user_by_uuid(uuid)
resource_svc.delete(subject, resource) resource_svc.delete(subject, resource)

View File

@ -30,7 +30,7 @@ def get_by_uuid(user_id: str, user_svc: UserService = Depends()):
return user_svc.get_user_by_uuid(user_id) return user_svc.get_user_by_uuid(user_id)
@api.post("/create", response_model=User, tags=["Users"]) @api.post("/", response_model=User, tags=["Users"])
def create_user(uuid: str, user: User, user_svc: UserService = Depends()): def create_user(uuid: str, user: User, user_svc: UserService = Depends()):
subject = user_svc.get_user_by_uuid(uuid) subject = user_svc.get_user_by_uuid(uuid)
if subject.role != UserTypeEnum.ADMIN: if subject.role != UserTypeEnum.ADMIN:

View File

@ -0,0 +1,37 @@
import { NextResponse } from "next/server";
import User from "@/utils/models/User";
export async function POST(request: Request) {
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/resource`;
try {
const resourceData = await request.json();
console.log("RESOURCE DATA", JSON.stringify(resourceData));
const { searchParams } = new URL(request.url);
const uuid = searchParams.get("uuid");
// Send the POST request to the backend
const response = await fetch(`${apiEndpoint}?uuid=${uuid}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(resourceData),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const createdResource: User = await response.json();
return NextResponse.json(createdResource, { status: response.status });
} catch (error) {
console.error("Error creating resource:", error);
return NextResponse.json(
{ error: "Failed to create resource" },
{ status: 500 }
);
}
}

View File

@ -0,0 +1,37 @@
import { NextResponse } from "next/server";
import User from "@/utils/models/User";
export async function POST(request: Request) {
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/service`;
try {
const serviceData = await request.json();
console.log("SERVICE DATA", JSON.stringify(serviceData));
const { searchParams } = new URL(request.url);
const uuid = searchParams.get("uuid");
// Send the POST request to the backend
const response = await fetch(`${apiEndpoint}?uuid=${uuid}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(serviceData),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const createdService: User = await response.json();
return NextResponse.json(createdService, { status: response.status });
} catch (error) {
console.error("Error creating service:", error);
return NextResponse.json(
{ error: "Failed to create service" },
{ status: 500 }
);
}
}

View File

@ -2,14 +2,10 @@ import { NextResponse } from "next/server";
import User from "@/utils/models/User"; import User from "@/utils/models/User";
export async function POST(request: Request) { export async function POST(request: Request) {
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/user/create`; const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/user`;
try { try {
const userData = await request.json(); const userData = await request.json();
userData.role = userData.role.toUpperCase();
userData.program = userData.program.map((program: string) =>
program.toUpperCase()
);
console.log("USER DATA", JSON.stringify(userData)); console.log("USER DATA", JSON.stringify(userData));

View File

@ -10,6 +10,7 @@ import { useEffect, useState } from "react";
export default function Page() { export default function Page() {
const [resources, setResources] = useState<Resource[]>([]); const [resources, setResources] = useState<Resource[]>([]);
const [uuid, setUuid] = useState<string>("");
useEffect(() => { useEffect(() => {
async function getResources() { async function getResources() {
@ -22,6 +23,8 @@ export default function Page() {
return; return;
} }
setUuid(data.user.id);
const userListData = await fetch( const userListData = await fetch(
`${process.env.NEXT_PUBLIC_HOST}/api/resource/all?uuid=${data.user.id}` `${process.env.NEXT_PUBLIC_HOST}/api/resource/all?uuid=${data.user.id}`
); );
@ -38,7 +41,11 @@ export default function Page() {
<div className="min-h-screen flex flex-col"> <div className="min-h-screen flex flex-col">
{/* icon + title */} {/* icon + title */}
<PageLayout title="Resources" icon={<BookmarkIcon />}> <PageLayout title="Resources" icon={<BookmarkIcon />}>
<ResourceTable data={resources} setData={setResources} /> <ResourceTable
data={resources}
setData={setResources}
uuid={uuid}
/>
</PageLayout> </PageLayout>
</div> </div>
); );

View File

@ -10,6 +10,7 @@ import { useEffect, useState } from "react";
export default function Page() { export default function Page() {
const [services, setServices] = useState<Service[]>([]); const [services, setServices] = useState<Service[]>([]);
const [uuid, setUuid] = useState<string>("");
useEffect(() => { useEffect(() => {
async function getServices() { async function getServices() {
@ -22,6 +23,8 @@ export default function Page() {
return; return;
} }
setUuid(data.user.id);
const serviceListData = await fetch( const serviceListData = await fetch(
`${process.env.NEXT_PUBLIC_HOST}/api/service/all?uuid=${data.user.id}` `${process.env.NEXT_PUBLIC_HOST}/api/service/all?uuid=${data.user.id}`
); );
@ -37,7 +40,11 @@ export default function Page() {
<div className="min-h-screen flex flex-col"> <div className="min-h-screen flex flex-col">
{/* icon + title */} {/* icon + title */}
<PageLayout title="Services" icon={<ClipboardIcon />}> <PageLayout title="Services" icon={<ClipboardIcon />}>
<ServiceTable data={services} setData={setServices} /> <ServiceTable
data={services}
setData={setServices}
uuid={uuid}
/>
</PageLayout> </PageLayout>
</div> </div>
); );

View File

@ -18,6 +18,7 @@ import { Tag } from "../TagsInput/Tag";
type ResourceTableProps = { type ResourceTableProps = {
data: Resource[]; data: Resource[];
setData: Dispatch<SetStateAction<Resource[]>>; setData: Dispatch<SetStateAction<Resource[]>>;
uuid: string;
}; };
/** /**
@ -25,13 +26,17 @@ type ResourceTableProps = {
* @param props.data Stateful list of resources to be displayed by the table * @param props.data Stateful list of resources to be displayed by the table
* @param props.setData State setter for the list of resources * @param props.setData State setter for the list of resources
*/ */
export default function ResourceTable({ data, setData }: ResourceTableProps) { export default function ResourceTable({
data,
setData,
uuid,
}: ResourceTableProps) {
const columnHelper = createColumnHelper<Resource>(); const columnHelper = createColumnHelper<Resource>();
const [programPresets, setProgramPresets] = useState([ const [programPresets, setProgramPresets] = useState([
"domestic", "DOMESTIC",
"community", "COMMUNITY",
"economic", "ECONOMIC",
]); ]);
const resourceDetails: Details[] = [ const resourceDetails: Details[] = [
@ -137,6 +142,7 @@ export default function ResourceTable({ data, setData }: ResourceTableProps) {
setData={setData} setData={setData}
columns={columns} columns={columns}
details={resourceDetails} details={resourceDetails}
createEndpoint={`/api/resource/create?uuid=${uuid}`}
/> />
); );
} }

View File

@ -16,6 +16,7 @@ import { Tag } from "../TagsInput/Tag";
type ServiceTableProps = { type ServiceTableProps = {
data: Service[]; data: Service[];
setData: Dispatch<SetStateAction<Service[]>>; setData: Dispatch<SetStateAction<Service[]>>;
uuid: string;
}; };
/** /**
@ -23,23 +24,27 @@ type ServiceTableProps = {
* @param props.data Stateful list of services to be displayed by the table * @param props.data Stateful list of services to be displayed by the table
* @param props.setData State setter for the list of services * @param props.setData State setter for the list of services
*/ */
export default function ServiceTable({ data, setData }: ServiceTableProps) { export default function ServiceTable({
data,
setData,
uuid,
}: ServiceTableProps) {
const columnHelper = createColumnHelper<Service>(); const columnHelper = createColumnHelper<Service>();
const [programPresets, setProgramPresets] = useState([ const [programPresets, setProgramPresets] = useState([
"domestic", "DOMESTIC",
"community", "COMMUNITY",
"economic", "ECONOMIC",
]); ]);
const [requirementPresets, setRequirementPresets] = useState([ const [requirementPresets, setRequirementPresets] = useState([
"anonymous", "ANONYMOUS",
"confidential", "CONFIDENTIAL",
"referral required", "REFERRAL REQUIRED",
"safety assessment", "SAFETY ASSESSMENT",
"intake required", "INTAKE REQUIRED",
"income eligibility", "INCOME ELIGIBILITY",
"initial assessment", "INITIAL ASSESSMENT",
]); ]);
const serviceDetails: Details[] = [ const serviceDetails: Details[] = [
@ -165,6 +170,7 @@ export default function ServiceTable({ data, setData }: ServiceTableProps) {
setData={setData} setData={setData}
columns={columns} columns={columns}
details={serviceDetails} details={serviceDetails}
createEndpoint={`/api/service/create?uuid=${uuid}`}
/> />
); );
} }

View File

@ -31,15 +31,15 @@ export default function UserTable({ data, setData, uuid }: UserTableProps) {
const columnHelper = createColumnHelper<User>(); const columnHelper = createColumnHelper<User>();
const [rolePresets, setRolePresets] = useState([ const [rolePresets, setRolePresets] = useState([
"admin", "ADMIN",
"volunteer", "VOLUNTEER",
"employee", "EMPLOYEE",
]); ]);
const [programPresets, setProgramPresets] = useState([ const [programPresets, setProgramPresets] = useState([
"domestic", "DOMESTIC",
"community", "COMMUNITY",
"economic", "ECONOMIC",
]); ]);
const userDetails: Details[] = [ const userDetails: Details[] = [

View File

@ -23,12 +23,8 @@ const TagsInput: React.FC<TagsInputProps> = ({
const [cellSelected, setCellSelected] = useState(false); const [cellSelected, setCellSelected] = useState(false);
// TODO: Add tags to the database and remove the presetValue and lowercasing // TODO: Add tags to the database and remove the presetValue and lowercasing
const [tags, setTags] = useState<Set<string>>( const [tags, setTags] = useState<Set<string>>(new Set(presetValue));
new Set(presetValue.map((tag) => tag.toLowerCase())) const [options, setOptions] = useState<Set<string>>(new Set(presetOptions));
);
const [options, setOptions] = useState<Set<string>>(
new Set(presetOptions.map((option) => option.toLowerCase()))
);
const [filteredOptions, setFilteredOptions] = useState<Set<string>>( const [filteredOptions, setFilteredOptions] = useState<Set<string>>(
new Set(presetOptions) new Set(presetOptions)
); );
@ -44,7 +40,6 @@ const TagsInput: React.FC<TagsInputProps> = ({
}; };
const handleOutsideClick = (event: MouseEvent) => { const handleOutsideClick = (event: MouseEvent) => {
console.log(dropdown.current);
if ( if (
dropdown.current && dropdown.current &&
!dropdown.current.contains(event.target as Node) !dropdown.current.contains(event.target as Node)

View File

@ -11,6 +11,7 @@ export const Tag = ({ children, handleDelete, active = false }: TagProps) => {
return ( return (
<span <span
className={`font-normal bg-purple-100 text-gray-800 flex flex-row p-1 px-2 rounded-lg`} className={`font-normal bg-purple-100 text-gray-800 flex flex-row p-1 px-2 rounded-lg`}
style={{ textTransform: "none" }}
> >
{children} {children}
{active && handleDelete && ( {active && handleDelete && (