Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tutosrive/factus_challenge/llms.txt

Use this file to discover all available pages before exploring further.

The Factus Challenge frontend lives in the fr-v1/ directory and is a fully static HTML application built with ES modules. There is no build step, no bundler, and no framework — you can open index.html directly in a browser or serve the folder from any static host. All JavaScript is loaded as native ES modules via <script type="module">, and each page controller is a class of pure static methods.

Technology Stack

HTML5 + Bootstrap 5.3.3

Uses the Bootstrap 5.3.3 Vapor dark theme, loaded from resources/utils/bootstrap-5.3.3/. The entire layout relies on Bootstrap utility classes — no custom CSS grid.

Vanilla JS ES Modules

All logic lives in .mjs files under resources/js/. Each view is an exported default class with only static methods; the classes throw on construction.

Tabulator 6.3

Tabulator 6.3 powers every data table. Progressive-scroll loading, column tooltips, custom cell formatters, and footer action buttons are used throughout.

Luxon 3

Luxon 3 handles all date parsing and formatting. Dates from the API arrive as dd-MM-yyyy hh:mm:ss a and are displayed in a long Spanish locale format.
Additional bundled libraries:
  • Bootstrap Popper (resources/utils/popper/) — powers dropdowns and tooltips
  • Custom utilities in resources/utils/own/:
    • helpers.jsHelpers class
    • toast.jsToast class
    • popup.jsPopup / Modal class
    • icons.jsicons object of SVG strings
    • dialog.js — base Dialog class extended by Popup

Directory Structure

fr-v1/
├── index.html                  # SPA shell — loads navigation and router (index.mjs)
├── favicon.ico
├── pages/                      # Standalone HTML pages (each reuses the same shell layout)
│   ├── about.html
│   ├── cliente.html
│   ├── factus.html
│   └── factusget.html
└── resources/
    ├── assets/
    │   ├── config.json         # Backend URL configuration (single field: "url")
    │   └── ciudades.json       # Municipality data (fallback / static reference)
    ├── css/
    │   └── styles.css          # Custom styles on top of Bootstrap Vapor
    ├── html/                   # Partial HTML templates loaded dynamically by JS modules
    │   ├── about.html
    │   ├── clientes.html
    │   ├── factus.html
    │   ├── inicio.html
    │   ├── productos.html
    │   └── search_factus.html
    ├── js/                     # ES module page controllers
    │   ├── index.mjs           # App bootstrap + router
    │   ├── inicio.mjs          # Home page
    │   ├── factus.mjs          # Invoices CRUD (Factus class)
    │   ├── clientes.mjs        # Clients CRUD (Clientes class)
    │   ├── factusearch.mjs     # Invoice search + PDF download (FactuSearch class)
    │   ├── about.mjs           # About page (About class)
    │   └── customs.mjs         # Shared UI utilities (exported functions)
    └── utils/                  # Vendor libs + custom utilities
        ├── bootstrap-5.3.3/
        ├── tabulator-6.3/
        ├── luxon3x.min.js
        ├── popper/
        └── own/
            ├── helpers.js
            ├── toast.js
            ├── popup.js
            ├── dialog.js
            └── icons.js

Configuration

The only thing you need to change to point the frontend at a different backend is the single-field config.json file. On startup, index.mjs fetches this file and writes the URL to window.urlAPI, which every module then reads as a global.
resources/assets/config.json
{
  "url": "http://localhost:4500"
}
Change url to the address of your deployed backend (e.g. https://api.myserver.com) and the entire frontend will switch targets without any other modification.

How the Router Works

index.mjs defines a single App class. When the page loads, App.main():
1

Fetch config

Reads config.json and stores config.url in window.urlAPI. Also registers shared globals (window.Tabulator, window.Toast, window.Modal, window.Helpers, window.icons, window.DateTime, etc.).
2

Verify backend connection

Calls GET ${urlAPI}/. If the response status is 200 the router continues; otherwise a danger Toast is shown.
3

Read current page

Extracts the trailing filename from window.location.href using the regex /[^/]+\.html$/ — e.g. factus.html.
4

Dynamic import

Passes the filename to App.#mainMenu(option), which uses a switch statement to dynamically import() the matching .mjs module and calls its .init() static method.
resources/js/index.mjs (router excerpt)
switch (option) {
  case 'index.html':
    App.#loadHome()
    break
  case 'factus.html':
    const { default: Factus } = await import('./factus.mjs')
    Factus.init()
    break
  case 'cliente.html':
    const { default: Clientes } = await import('./clientes.mjs')
    Clientes.init()
    break
  case 'about.html':
    const { default: About } = await import('./about.mjs')
    About.init()
    break
  case 'factusget.html':
    const { default: FactuSearch } = await import('./factusearch.mjs')
    FactuSearch.init()
    break
}

Custom Utility Classes

All utility classes are exposed as window globals by index.mjs so every lazily-loaded module can use them without additional imports.
Defined in resources/utils/own/helpers.js. Exposes common operations needed by all page controllers.
MethodSignatureDescription
fetchJSONfetchJSON(url, data?)Wraps fetch, auto-serialises an Object body to JSON, returns parsed JSON. Always resolves (errors returned as plain objects).
fetchTextfetchText(url, container?)Fetches an HTML partial. If container (CSS selector) is provided, injects the HTML there; otherwise returns the raw string.
toOptionListtoOptionList({ items, value, text, selected?, firstOption? })Builds a string of <option> elements from an array of objects. Used to populate every <select> in the app.
okFormokForm(formSelector, callBack?)Triggers native HTML5 form validation; returns true if valid. Accepts an optional extra validation callback.
selectOptionByTextselectOptionByText(select, text)Finds and selects a <select> option by its visible text — used when pre-filling edit forms.
idRandomidRandom(prefix?)Returns a zero-padded 14-digit random numeric string (used for unique modal/popover IDs).
flat / flattenflat(data) / flatten(obj, final?)Recursively flattens nested objects — useful for working with joined API responses.
// Example: populating a select from the API
const response = await Helpers.fetchJSON(`${urlAPI}/get-data/payment_method`)
const options = Helpers.toOptionList({
  items: response.data,
  value: 'id',
  text: 'name',
  firstOption: 'Seleccione un método de pago',
})
document.querySelector('#pago').innerHTML = options
Defined in resources/utils/own/toast.js. Displays a slide-in notification anchored to a <dialog> element appended to <body>.
Toast.show({
  title: 'Sistema de ventas',       // optional header text
  message: 'Cliente creado',        // supports HTML
  mode: 'success',                  // 'info' | 'success' | 'warning' | 'danger'
  duration: 3000,                   // auto-dismiss after N ms (default 3000)
  error: someError,                 // if provided, also logs to console.error
})
Each mode maps to a Bootstrap icon: checkCircleFill (success), infoCircleFill (info), exclamationCircleFill2 (warning), xCircleFill (danger).
Defined in resources/js/customs.mjs. Exported as named exports, re-exposed globally as window.Customs.
ExportDescription
classesModalStandard CSS class string applied to every Modal'position-absolute top-50 start-50 translate-middle bg-dark col-12 col-sm-10 col-md-9 col-lg-8 col-xl-7'
showInfoAboutUse(section)Shows a usage hint Toast on first/second visit to a section, tracked via localStorage.
toastBeforeAddRecord(msg?, just?)Shows a warning Toast when a form is submitted while invalid.
popover(title, html, buttons, classPop?)Creates and appends a native popover element to <body> with a header, content area, and footer buttons.
showPopover(pop)Calls pop.showPopover() and blurs the rest of the page body (filter: blur(2px)).
closePopover(pop)Removes the popover element and clears the blur effect.
new_client()Opens pages/cliente.html in a new tab — triggered from within the invoice creation form to allow adding a customer on the fly.
Defined in resources/utils/own/icons.js. A plain export default object where each key is a descriptive name and each value is an SVG string. Used inline in button HTML. Exposed as window.icons.Key icons used by the UI: icons.plusSquare (add row), icons.edit (edit row), icons.delete (delete row), icons.deleteWhite / icons.editWhite (modal submit buttons), icons.xLg (cancel), icons.pdf_icon1 (PDF download).

Build docs developers (and LLMs) love