This is a sample project using TypeScript and an event-driven approach.
Screen 1 | Screen 2 |
---|---|
![]() |
![]() |
- We should be able to run it using the instructions in this README.
- The exam list and detail views should display data from the API properly based on the wireframe above.
- The user experience should be intuitive and user-friendly.
- Your solution must respect the constraints above.
- Typescript setup
- Prettier configuration
- Script configuration
The frontend is built using Web Components and custom elements to encapsulate logic and markup. TypeScript provides type safety and tooling.
An event-driven architecture with producers, broker, and consumers is used for loose coupling. Key components are:
app-events
- Event broker that fetches data and dispatches eventsapp-router
- Event consumer that listens for navigation and renders views.app-view-toggle
- Event producer that emits custom events to fetch data for the active view.
app-router
- Client side router implementation. Component is implemented as view outlet. Listens for eventrouter-change
to determine which view to display.RouterHandler
- Events are handled in RouterHandler class instance. It listens for changes to window url to
app-events
- listens and fetches data, then dispatches examsDataLoaded
Example:
/**
* Example usage
* Fetches exam data from the API and emits a custom event with the data.
*
* @fires AppEvents#eb-examsData - Emits event with exams data payload.
*/
private async fetchExamsData(): Promise<void> {
const url = `${this.baseApiUrl}/exams`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const examsData = await response.json();
// Emitting a custom event with the exams data.
this.dispatchEvent(new CustomEvent('eb-examsData', {
detail: examsData,
bubbles: true,
composed: true,
}));
} catch (error) {
console.error('Failed to fetch exams data:', error);
// Handle error state appropriately
}
}
// Example of dispatching a request for exams data from a producer
document.dispatchEvent(new CustomEvent('requestExamsData'));
app-view-toggle
- listens and renders the app-exams-view
app-exams-view
- Renders the Exams view UI and handles exam data events.app-students-view
- Not implemented, placeholder component for /students This decouples the data loading from the view rendering.
In the entry initialization of the app, consideration for user experience is taken into account by preloading components that are not dependent on data fetch operations, such as app-header
and app-footer
.
These elements typically contain static information and good for giving the user a sense of immediate interaction and feedback when they load the application. By ensuring that these components are loaded first, users are presented with a complete frame of the application UI, thus enhancing the perceived performance of the app and contributing to a seamless user experience.
The initialize method uses Promise.all
to load these components in parallel, further optimizing the loading time and ensuring that the structural components of the UI are rendered as quickly as possible, regardless of the status of data-dependent components or network latency in fetching dynamic content.
Considerations for mouse events considered for interactive elements such as the side navigation and table rows.
The TypeScript project is configured in tsconfig.json.
- Components are authored in .ts files.
tsc
compiles to .js files in static/js folder.- Build is run on yarn build script.
/static/index.html
- Entry point that loads index.jsindex.ts
- Bootstraps the app by loadingapp-events
andapp-router
andcomponents/
- Web components for UIviews/
- Top level view components
This architecture allows for a scalable and maintainable frontend by decoupling concerns into reusable components with typed interfaces. The eventing scheme reduces direct dependencies between components.
- Browser
popstate
has some issues. We can address this by adding an event listener for windowpopstate
event. It would look something like this:- Listens for the browser's popstate event to handle browser navigation (e.g., back/forward).
- Listens for click events on anchor tags to intercept navigation requests.
- 1 Uses the history.pushState method to update the URL without a page reload.
- 1 Dispatches a custom
router-change
event that theapp-router
component can listen for to update the displayed view.
- Add loading indicators for page "busy" operations
- Keyboard navigation for accessibility
- Missing tests - tbd
Updating the UI after the initial API request was not addressed as stated in the project README.
-
To use the application and ensure that the UI displays the most current data:
-
Navigate through the application
- The UI updates automatically whenever you change the path. This is because the app-router listens for changes in the URL and triggers the relevant components to update the view.
- Refresh data manually: If you need the latest data for exams, simply click on the "Exams" tab.
This action emits a
requestExamsData
event, which theapp-events
component listens for. - Upon detecting this event,
app-events
fetches the most recent data from the API and dispatches aneb-examsData
event. - The UI components responsible for displaying exam data listen for this event and update the view accordingly with the new data.