Skip to content

Commit 34ee26f

Browse files
refactor: changes the API route and method
1 parent e5fbe6e commit 34ee26f

2 files changed

Lines changed: 50 additions & 104 deletions

File tree

frontend/src/domains/jobs/application/useJobsData.ts

Lines changed: 37 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,44 @@
11
import {
2-
fetchJobFiles,
3-
fetchJobsByFile,
2+
fetchJobsByAPI,
43
runScraperRequest,
54
} from "@/domains/jobs/infrastructure/jobsApi";
6-
import type { Job, JobFile, JobsMeta } from "@/domains/jobs/domain/job.types";
5+
import type { Job, JobsResponse } from "@/domains/jobs/domain/job.types";
76
import { useCallback, useEffect, useState } from "react";
87

9-
const EMPTY_META: JobsMeta = { file: "", modifiedAt: null, total: 0 };
8+
export type JobsPaginationMeta = Omit<JobsResponse, "jobs">;
109

11-
export function useJobsData(initialSelectedFile = "") {
12-
const [files, setFiles] = useState<JobFile[]>([]);
13-
const [selectedFile, setSelectedFile] = useState(initialSelectedFile);
10+
const EMPTY_META: JobsPaginationMeta = {
11+
total: 0,
12+
hasNext: false,
13+
hasPrev: false,
14+
page: 0,
15+
limit: 0,
16+
totalPages: 0,
17+
};
18+
19+
export function useJobsData(page: number = 1, limit: number = 5) {
1420
const [jobs, setJobs] = useState<Job[]>([]);
15-
const [meta, setMeta] = useState<JobsMeta>(EMPTY_META);
21+
const [meta, setMeta] = useState<JobsPaginationMeta>(EMPTY_META);
1622
const [loading, setLoading] = useState(false);
1723
const [scraping, setScraping] = useState(false);
1824
const [error, setError] = useState("");
1925

20-
const loadFiles = useCallback(async () => {
21-
const foundFiles = await fetchJobFiles();
22-
setFiles(foundFiles);
23-
return foundFiles;
24-
}, []);
25-
26-
const loadJobs = useCallback(async (fileName: string) => {
26+
const loadJobs = useCallback(async () => {
2727
setLoading(true);
2828
setError("");
2929

3030
try {
31-
const data = await fetchJobsByFile(fileName);
32-
setJobs(data.jobs);
31+
const data = await fetchJobsByAPI(page, limit);
32+
setJobs(data.jobs ?? []);
33+
3334
setMeta({
34-
file: data.file,
35-
modifiedAt: data.modifiedAt,
36-
total: data.total,
35+
total: data.total ?? 0,
36+
hasNext: data.hasNext ?? false,
37+
hasPrev: data.hasPrev ?? false,
38+
page: data.page ?? page,
39+
limit: data.limit ?? limit,
40+
totalPages: data.totalPages ?? 0,
3741
});
38-
39-
if (data.file && data.file !== fileName) {
40-
setSelectedFile(data.file);
41-
}
4242
} catch (err: unknown) {
4343
setJobs([]);
4444
setMeta(EMPTY_META);
@@ -50,57 +50,30 @@ export function useJobsData(initialSelectedFile = "") {
5050
} finally {
5151
setLoading(false);
5252
}
53-
}, []);
53+
}, [page, limit]);
5454

5555
useEffect(() => {
56-
async function initializeFiles() {
57-
const foundFiles = await loadFiles();
58-
if (foundFiles[0]?.file) {
59-
setSelectedFile((current) => current || foundFiles[0].file);
60-
}
61-
}
56+
let isMounted = true;
6257

63-
initializeFiles().catch(() => {
64-
setError("Nao foi possivel listar arquivos .xlsx da pasta output.");
65-
});
66-
}, [loadFiles]);
58+
const initialize = async () => {
59+
if (!isMounted) return;
60+
await loadJobs();
61+
};
6762

68-
useEffect(() => {
69-
const syncState = setTimeout(() => {
70-
if (!selectedFile) {
71-
setJobs([]);
72-
setMeta(EMPTY_META);
73-
return;
74-
}
63+
initialize();
7564

76-
loadJobs(selectedFile);
77-
}, 0);
78-
79-
return () => clearTimeout(syncState);
80-
}, [selectedFile, loadJobs]);
65+
return () => {
66+
isMounted = false;
67+
};
68+
}, [loadJobs]);
8169

8270
const triggerScraper = useCallback(async () => {
8371
setScraping(true);
8472
setError("");
8573

8674
try {
8775
await runScraperRequest();
88-
const foundFiles = await loadFiles();
89-
const nextFile = foundFiles[0]?.file ?? "";
90-
91-
if (!nextFile) {
92-
setSelectedFile("");
93-
setJobs([]);
94-
setMeta(EMPTY_META);
95-
return;
96-
}
97-
98-
if (nextFile !== selectedFile) {
99-
setSelectedFile(nextFile);
100-
return;
101-
}
102-
103-
await loadJobs(nextFile);
76+
await loadJobs();
10477
} catch (err: unknown) {
10578
setError(
10679
err instanceof Error
@@ -110,12 +83,9 @@ export function useJobsData(initialSelectedFile = "") {
11083
} finally {
11184
setScraping(false);
11285
}
113-
}, [loadFiles, loadJobs, selectedFile]);
86+
}, [loadJobs]);
11487

11588
return {
116-
files,
117-
selectedFile,
118-
setSelectedFile,
11989
jobs,
12090
meta,
12191
loading,

frontend/src/domains/jobs/infrastructure/jobsApi.ts

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { JobFile, JobsResponse } from "@/domains/jobs/domain/job.types";
1+
import type { JobsResponse } from "@/domains/jobs/domain/job.types";
22

33
function normalizeBaseUrl(value: string | undefined): string {
44
return typeof value === "string" ? value.trim().replace(/\/+$/, "") : "";
@@ -57,38 +57,15 @@ function readMessage(payload: unknown): string | undefined {
5757
return undefined;
5858
}
5959

60-
export async function fetchJobFiles(): Promise<JobFile[]> {
61-
const response = await fetch(buildApiUrl("/jobs/files"), {
62-
credentials: "include",
63-
});
64-
const payload = (await readPayload(response)) as { files?: unknown } & Record<
65-
string,
66-
unknown
67-
>;
68-
69-
if (!response.ok) {
70-
throw buildError(
71-
readMessage(payload),
72-
"Falha ao listar arquivos de vagas.",
73-
);
74-
}
75-
76-
if (!Array.isArray(payload.files)) {
77-
return [];
78-
}
60+
export async function fetchJobsByAPI(page?: number, limit?: number): Promise<JobsResponse> {
61+
const queryParams = new URLSearchParams();
62+
if (page !== undefined) queryParams.set("page", String(page));
63+
if (limit !== undefined) queryParams.set("limit", String(limit));
7964

80-
return payload.files.filter(
81-
(entry): entry is JobFile =>
82-
!!entry &&
83-
typeof entry === "object" &&
84-
"file" in entry &&
85-
typeof (entry as { file: unknown }).file === "string",
86-
);
87-
}
65+
const queryString = queryParams.toString();
66+
const urlPath = queryString ? `/jobs/search?${queryString}` : `/jobs/search`;
8867

89-
export async function fetchJobsByFile(fileName: string): Promise<JobsResponse> {
90-
const suffix = fileName ? `?file=${encodeURIComponent(fileName)}` : "";
91-
const response = await fetch(buildApiUrl(`/jobs${suffix}`), {
68+
const response = await fetch(buildApiUrl(urlPath), {
9269
credentials: "include",
9370
});
9471
const payload = (await readPayload(response)) as Record<string, unknown>;
@@ -99,13 +76,12 @@ export async function fetchJobsByFile(fileName: string): Promise<JobsResponse> {
9976

10077
return {
10178
jobs: Array.isArray(payload.jobs) ? payload.jobs : [],
102-
file: typeof payload.file === "string" ? payload.file : "",
103-
modifiedAt:
104-
typeof payload.modifiedAt === "string" ||
105-
typeof payload.modifiedAt === "number"
106-
? payload.modifiedAt
107-
: null,
10879
total: Number(payload.total || 0),
80+
hasNext: Boolean(payload.hasNext),
81+
hasPrev: Boolean(payload.hasPrev),
82+
page: Number(payload.page || 0),
83+
limit: Number(payload.limit || 0),
84+
totalPages: Number(payload.totalPages || 0),
10985
};
11086
}
11187

0 commit comments

Comments
 (0)