Skip to content
This repository was archived by the owner on Nov 5, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README-nisha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Thoughts while approaching this project

## Understanding the existing code

After installing and cloning this repository, I had a look at the existing code to work out what was already in place. I created a basic function to fetch the service result and log it to the console in order to play with it a little.

After an initial investigation, I decided which files and components I wanted to create and how I wanted to handle the jobs data. I decided to handle the jobs object inside `QuestionOne` and to pass the array into a `JobsList` component. I would also pass a callback function that would call the service and request the jobs based on the search term. This callback would be passed to a `SearchField` component.

Next, I created the `JobsList`. For the first iteration, all it did was accept a list of jobs and map them to a list with the necessary information. There was no styling or anything - that can be added later.

The next step was to create the search box and functionality - the `SearchField`. I first set up the functional component with an input box that is controlled by a ref. I added a button and set it up to expect an onSearch callback, which will come from `QuestionOne`. I decided to use a button for now, just to make sure the link between the request and data display worked as expected.

I then used the new components in `QuestionOne` and tested manually to make sure things were in place. When linking everything together, I noticed some issues with the `Pick` description of the service. As the service didn't filter the data, and we need to display the location plus use the ID, I adjusted the return type of the `IDataService` functions.

Once satisfied with all of this, I next looked at the submit button. I removed it and the ref, and created a function called `onChange` which could be passed to the input. At this point, I ran the tests to ensure everything was okay. I adjusted the label of my input to match the tests, reran and everything passed!

I then added some styling to the `JobsList` to make each job item clearer and a little prettier. I formatted the datetime to strings and separated them into date and time components.

Future extensions could include

* better styling
* animations when list appears/disappears
* placeholder where jobs list should be to indicate no jobs are available
* filters
4 changes: 2 additions & 2 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export interface Job {
}

export interface IDataService {
getJobs: () => Promise<Pick<Job, 'name' | 'start' | 'end'>[]>;
getJobs: () => Promise<Job[]>;
getJobsWithSearchTerm: (
searchTerm: string
) => Promise<Pick<Job, 'name' | 'start' | 'end'>[]>;
) => Promise<Job[]>;
}
15 changes: 15 additions & 0 deletions src/components/JobsList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.job__item {
display: flex;
flex-direction: column;
border: 1px solid black;
padding: 1em;
border-radius: 25px;
}

.title {
font-weight: bolder;
}

.jobs {
list-style-type: none;
}
31 changes: 31 additions & 0 deletions src/components/JobsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { FC } from "react";
import { Job } from "../common/types";
import './JobsList.css';

type Props = {
jobs: Job[];
}

const jobMapper = (job: Job) => {
return (
<li key={job.id} className='job__item'>
<div className="title">{job.name}</div>
<div>Location: {job.location}</div>
<div>Start date: {new Date(job.start).toDateString()}</div>
<div>Start time: {new Date(job.start).toTimeString()}</div>
<div>End date: {new Date(job.end).toDateString()}</div>
<div>End time: {new Date(job.end).toTimeString()}</div>
</li>
)
}

export const JobsList: FC<Props> = ({ jobs }) => {
return (
<div>
Here are the current jobs available based on your search:
<ul className="jobs">
{jobs.map(jobMapper)}
</ul>
</div>
)
}
30 changes: 30 additions & 0 deletions src/components/SearchField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ChangeEvent, FC, useCallback } from "react";

type Props = {
onSearch: (value: string) => void;
onClear: () => void;
}

export const SearchField: FC<Props> = ({ onSearch, onClear }) => {
const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length > 3) {
onSearch(e.target.value)
}

if (e.target.value === '') {
onClear()
}
}, [onSearch, onClear])


return (
<div>
Please type here to search for the jobs you would like to find:
<form>
<label htmlFor="search">Search:
<input onChange={onChange} type='text' id={'search'} name='search' />
</label>
</form>
</div >
)
}
24 changes: 17 additions & 7 deletions src/question-one/QuestionOne.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
import React from 'react';
import { IDataService } from "../common/types";
import React, { useCallback, useState } from 'react';
import { IDataService, Job } from "../common/types";
import { JobsList } from '../components/JobsList';
import { SearchField } from '../components/SearchField';
import { SectionGroup } from '../components/section/SectionGroup';
import { SectionPanel } from '../components/section/SectionPanel';
import './QuestionOne.css';

export const QuestionOne: React.FC<{ service: IDataService }> = ({
service,
}) => {
const [jobs, setJobs] = useState<Job[]>([]);

const searchForJobs = useCallback(async (searchTerm: string) => {
const data = await service.getJobsWithSearchTerm(searchTerm);
setJobs(data)
}, [service, setJobs])

const clearJobs = useCallback(() => {
setJobs([]);
}, [setJobs])

return (
<SectionGroup>
<SectionPanel>
<section className="jobs">
Please refer to src/INSTRUCTIONS.md

<div className="jobs__search">
{/* Render a search field here... */}
<SearchField onSearch={searchForJobs} onClear={clearJobs} />
</div>

<div className="jobs__list">
{/* Render a list of results here... */}
<JobsList jobs={jobs}></JobsList>
</div>
</section>
</SectionPanel>
Expand Down