The frontend is a React 19 single-page application built and served by Vite. It runs on port 4000 during development and communicates with the Express backend over plain HTTP atDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/titobrian97/Prueba-tecnica-ts-node---gestion-de-csv/llms.txt
Use this file to discover all available pages before exploring further.
http://localhost:3000. The entire user interface is driven by a lightweight state machine encoded in the APP_STATUS constant — this single piece of state determines which UI section is visible, whether form controls are disabled, and what label appears on the submit button. TypeScript is used throughout: component props, state variables, service return types, and shared domain types are all explicitly typed.
App State Machine
TheAPP_STATUS object defines every state the application can occupy:
| Status | Meaning |
|---|---|
idle | Initial state — the file input is rendered but no file has been selected yet. |
ready_upload | A file has been selected; the upload button becomes visible. |
uploading | The SendCsv call is in-flight; the input and button are disabled and the button label reads “Cargando”. |
error | The upload or parsing failed; the form remains visible so the user can try again. |
ready_usage | Upload succeeded; the upload form is unmounted and the <Search> component is rendered. |
App via useState<AppStatusType> and are driven by user interactions and the resolved values of the service functions.
Component Breakdown
App
Root component. Owns all state, handles file selection and form submission, and conditionally renders either the upload form or
<Search>.Search
Receives the initial
dataCsv prop, manages a controlled search input, debounces the query at 300 ms, and re-renders the row list on each response.App Component
App holds four pieces of state: appStatus, file, data, and error. The upload form is rendered whenever appStatus is not ready_usage. The submit button is shown only when appStatus is ready_upload or uploading:
App calls SendCsv(file) and branches on the returned [data?, Error?] tuple. A non-empty error triggers a sonner toast and transitions to error. A successful response with a non-empty data.data array stores the rows in state, fires a success toast, and transitions to ready_usage, which swaps the form for <Search dataCsv={data} />.
Search Component
Search accepts dataCsv (the initial full dataset from the upload response) and setAppStatus as props. It maintains its own local data state, initialised from dataCsv, and a search string state tied to the controlled input.
The raw search value is passed through useDebounce with a 300 ms delay:
useEffect fires whenever searchDebounced changes (and is non-empty), calling useSearch({ searchParam: searchDebounced }). The resolved data.data array is written to the local data state, causing React to re-render the result list. Each row is rendered as a <li> containing an <article> whose entries are iterated with Object.entries(user), displaying every column key and value in sequence.
Service Functions
Both service functions live insrc/Services/useGetApiData.tsx and return Promise<[Data?, Error?]> tuples, following a Go-style error-first result pattern.
SendCsv(file) — POST /api/files
SendCsv(file) — POST /api/files
Builds a On success,
FormData object, appends the File under the key "file", and POSTs it to the backend upload endpoint:data is the ApiResponse object { data: Record<string, string>[], message: string }. On network failure the catch branch returns [undefined, e] where e is the thrown Error.useSearch({ searchParam }) — GET /api/users?q=
useSearch({ searchParam }) — GET /api/users?q=
Constructs a query string from The resolved
searchParam and GETs the search endpoint:data contains { data: Record<string, string>[] } — matching rows from the backend filter. Despite the use prefix, this is not a React hook; it is a plain async function called imperatively inside a useEffect.TypeScript Types
All shared domain types are defined insrc/types.ts:
| Type | Usage |
|---|---|
Data | The parsed CSV rows held in both App state and passed as the dataCsv prop to Search. Can be undefined before a successful upload. |
ApiResponse | The JSON shape returned by both backend endpoints — a data array and a message string. |
AppStatusType | A union of all APP_STATUS values derived via typeof … [keyof typeof …], ensuring state can only ever be one of the five valid strings. |
Key Dependencies
| Package | Version | Role |
|---|---|---|
react | ^19.2.4 | Core UI library — component model, hooks, and concurrent rendering. |
react-dom | ^19.2.4 | DOM renderer for React — required alongside react to mount the app into the browser. |
sonner | ^2.0.7 | Lightweight toast notification library; used to surface upload success and error messages. |
use-debounce | ^10.1.1 | Provides useDebounce hook to delay the search query by 300 ms and prevent a fetch on every keystroke. |
debounce | ^3.0.0 | Utility debounce function included as a direct dependency alongside use-debounce. |
next-themes | ^0.4.6 | Theme management utility included as a dependency (available for light/dark mode switching). |
vite | ^8.0.4 | Dev server and bundler — provides HMR and the --port flag used to pin the server to port 4000. |
Dev Server
The Vite dev server is started on port 4000 via thedev script:
tsc -b (type-check and compile) followed by vite build, which outputs optimised static assets to the dist/ directory.
The frontend hardcodes
http://localhost:3000 as the API base URL in both SendCsv and useSearch. This works correctly during local development but will break in any deployed environment where the backend is not available at that exact address. For production you would need to replace these literals with an environment variable (for example import.meta.env.VITE_API_URL) and configure the correct value at build time.