From c6b552bf06676ba2e266e6266a0cc17c1ff467a1 Mon Sep 17 00:00:00 2001 From: nisha000 Date: Mon, 3 Oct 2022 14:54:24 +0100 Subject: [PATCH 1/3] feat: add core functionality for job search --- README-nisha.md | 15 +++++++++++++++ src/common/types.ts | 4 ++-- src/components/JobsList.tsx | 29 +++++++++++++++++++++++++++++ src/components/SearchField.tsx | 30 ++++++++++++++++++++++++++++++ src/question-one/QuestionOne.tsx | 23 +++++++++++++++++------ 5 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 README-nisha.md create mode 100644 src/components/JobsList.tsx create mode 100644 src/components/SearchField.tsx diff --git a/README-nisha.md b/README-nisha.md new file mode 100644 index 0000000..96e4ee6 --- /dev/null +++ b/README-nisha.md @@ -0,0 +1,15 @@ +# 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 :party-parrot. \ No newline at end of file diff --git a/src/common/types.ts b/src/common/types.ts index 7fbff30..5c09ade 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -8,8 +8,8 @@ export interface Job { } export interface IDataService { - getJobs: () => Promise[]>; + getJobs: () => Promise; getJobsWithSearchTerm: ( searchTerm: string - ) => Promise[]>; + ) => Promise; } diff --git a/src/components/JobsList.tsx b/src/components/JobsList.tsx new file mode 100644 index 0000000..f011af1 --- /dev/null +++ b/src/components/JobsList.tsx @@ -0,0 +1,29 @@ +import { FC } from "react"; +import { Job } from "../common/types"; + +type Props = { + jobs: Job[]; +} + +const jobMapper = (job: Job) => { + return ( +
  • +
    +
    {job.name}
    +
    {job.location}
    +
    {job.start}-{job.end}
    +
    +
  • + ) +} + +export const JobsList: FC = ({ jobs }) => { + return ( +
    + Here are the current jobs available based on your search: +
      + {jobs.map(jobMapper)} +
    +
    + ) +} \ No newline at end of file diff --git a/src/components/SearchField.tsx b/src/components/SearchField.tsx new file mode 100644 index 0000000..2423e97 --- /dev/null +++ b/src/components/SearchField.tsx @@ -0,0 +1,30 @@ +import { ChangeEvent, ChangeEventHandler, FC, useCallback, useEffect, useRef } from "react"; + +type Props = { + onSearch: (value: string) => void; + onClear: () => void; +} + +export const SearchField: FC = ({ onSearch, onClear }) => { + const onChange = useCallback((e: ChangeEvent) => { + if (e.target.value.length > 3) { + onSearch(e.target.value) + } + + if (e.target.value === '') { + onClear() + } + }, [onSearch, onClear]) + + + return ( +
    + Please type here to search for the jobs you would like to find: +
    + +
    +
    + ) +} \ No newline at end of file diff --git a/src/question-one/QuestionOne.tsx b/src/question-one/QuestionOne.tsx index fd12f51..831bebc 100644 --- a/src/question-one/QuestionOne.tsx +++ b/src/question-one/QuestionOne.tsx @@ -1,5 +1,7 @@ -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'; @@ -7,17 +9,26 @@ import './QuestionOne.css'; export const QuestionOne: React.FC<{ service: IDataService }> = ({ service, }) => { + const [jobs, setJobs] = useState([]); + + const searchForJobs = useCallback(async (searchTerm: string) => { + const data = await service.getJobsWithSearchTerm(searchTerm); + setJobs(data) + }, [service, setJobs]) + + const clearJobs = useCallback(() => { + setJobs([]); + }, [setJobs]) + return (
    - Please refer to src/INSTRUCTIONS.md -
    - {/* Render a search field here... */} +
    -
    + {/* Render a list of results here... */}
    From 5790af25819a8c2f2ea986a85fe1d980ebb8c470 Mon Sep 17 00:00:00 2001 From: nisha000 Date: Mon, 3 Oct 2022 15:24:31 +0100 Subject: [PATCH 2/3] feat: some styling for JobsList --- README-nisha.md | 11 ++++++++++- src/components/JobsList.css | 15 +++++++++++++++ src/components/JobsList.tsx | 16 +++++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 src/components/JobsList.css diff --git a/README-nisha.md b/README-nisha.md index 96e4ee6..db24e1f 100644 --- a/README-nisha.md +++ b/README-nisha.md @@ -12,4 +12,13 @@ The next step was to create the search box and functionality - the `SearchField` 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 :party-parrot. \ No newline at end of file +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 \ No newline at end of file diff --git a/src/components/JobsList.css b/src/components/JobsList.css new file mode 100644 index 0000000..870e42b --- /dev/null +++ b/src/components/JobsList.css @@ -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; +} \ No newline at end of file diff --git a/src/components/JobsList.tsx b/src/components/JobsList.tsx index f011af1..3df2b88 100644 --- a/src/components/JobsList.tsx +++ b/src/components/JobsList.tsx @@ -1,5 +1,6 @@ import { FC } from "react"; import { Job } from "../common/types"; +import './JobsList.css'; type Props = { jobs: Job[]; @@ -7,12 +8,13 @@ type Props = { const jobMapper = (job: Job) => { return ( -
  • -
    -
    {job.name}
    -
    {job.location}
    -
    {job.start}-{job.end}
    -
    +
  • +
    {job.name}
    +
    Location: {job.location}
    +
    Start date: {new Date(job.start).toDateString()}
    +
    Start time: {new Date(job.start).toTimeString()}
    +
    End date: {new Date(job.end).toDateString()}
    +
    End time: {new Date(job.end).toTimeString()}
  • ) } @@ -21,7 +23,7 @@ export const JobsList: FC = ({ jobs }) => { return (
    Here are the current jobs available based on your search: -
      +
        {jobs.map(jobMapper)}
    From 1ddf23a30cdcca2e634081590584e9e1758a2b10 Mon Sep 17 00:00:00 2001 From: nisha000 Date: Mon, 3 Oct 2022 15:30:08 +0100 Subject: [PATCH 3/3] fix: tidy files --- src/components/SearchField.tsx | 2 +- src/question-one/QuestionOne.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/SearchField.tsx b/src/components/SearchField.tsx index 2423e97..da0a683 100644 --- a/src/components/SearchField.tsx +++ b/src/components/SearchField.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, ChangeEventHandler, FC, useCallback, useEffect, useRef } from "react"; +import { ChangeEvent, FC, useCallback } from "react"; type Props = { onSearch: (value: string) => void; diff --git a/src/question-one/QuestionOne.tsx b/src/question-one/QuestionOne.tsx index 831bebc..9deb0d5 100644 --- a/src/question-one/QuestionOne.tsx +++ b/src/question-one/QuestionOne.tsx @@ -29,7 +29,6 @@ export const QuestionOne: React.FC<{ service: IDataService }> = ({
    - {/* Render a list of results here... */}