diff --git a/CHANGELOG.md b/CHANGELOG.md
index 823337a..1aa9955 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.6.0] - 2020-08-17
+
+### đ Bug Fixeroo
+
+### Added
+
+### Changed
+
+- Hide hidden jobs in search results - [#79](https://github.com/alexlee-dev/gh-jobs/issues/79)
+- Single `ErrorResponse` type for error responses - [#88](https://github.com/alexlee-dev/gh-jobs/issues/88)
+
+### Removed
+
+- Template Configuration - [#93](https://github.com/alexlee-dev/gh-jobs/issues/93)
+
+### Fixed
+
+- `unique()` function not working as expected, resulting in search results containing more entires than jobs in DB - [#85](https://github.com/alexlee-dev/gh-jobs/issues/85)
+- Now able to access `Details` page with a direct url - [#80](https://github.com/alexlee-dev/gh-jobs/issues/80)
+- `ProfileAccountStats` container width spilling out on mobile - [#93](https://github.com/alexlee-dev/gh-jobs/issues/93)
+
## [1.5.0] - 2020-08-15
### âšī¸ Button Redesign
diff --git a/cypress/integration/applicationError.spec.js b/cypress/integration/applicationError.spec.js
index ad19df7..c03f2ef 100644
--- a/cypress/integration/applicationError.spec.js
+++ b/cypress/integration/applicationError.spec.js
@@ -10,7 +10,7 @@ context("Application Error", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -18,7 +18,7 @@ context("Application Error", () => {
});
cy.route({
method: "GET",
- url: "/jobs/search?full_time=false&contract=false&description=react",
+ url: "/jobs/search?userId=&full_time=false&contract=false&description=react",
status: 200,
response: {},
delay: 1000,
diff --git a/cypress/integration/details.spec.js b/cypress/integration/details.spec.js
index a209950..ee43985 100644
--- a/cypress/integration/details.spec.js
+++ b/cypress/integration/details.spec.js
@@ -6,7 +6,7 @@ context("Details", () => {
cy.fixture("jobDetails").then((jobDetails) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/cypress/integration/directPageAccess.spec.js b/cypress/integration/directPageAccess.spec.js
index 3437edb..7027ee8 100644
--- a/cypress/integration/directPageAccess.spec.js
+++ b/cypress/integration/directPageAccess.spec.js
@@ -1,15 +1,24 @@
///
-context("Details", () => {
+context("Direct Page Access", () => {
beforeEach(() => {
cy.fixture("jobs50").then((jobsJson) => {
- cy.server();
- cy.route({
- method: "GET",
- url: "/jobs",
- status: 200,
- response: jobsJson,
- delay: 1000,
+ cy.fixture("jobDetails").then((jobDetailsJson) => {
+ cy.server();
+ cy.route({
+ method: "POST",
+ url: "/jobs",
+ status: 200,
+ response: jobsJson,
+ delay: 1000,
+ });
+ cy.route({
+ method: "GET",
+ url: "/jobs/f1884b46-ecb4-473c-81f5-08d9bf2ab3bb",
+ status: 200,
+ response: jobDetailsJson,
+ delay: 1000,
+ });
});
});
});
@@ -28,8 +37,8 @@ context("Details", () => {
cy.get("h1").should("have.text", "Create Account");
});
- it("Should be able to access '/jobs/:id' directly", () => {
- cy.visit("http://localhost:3000/jobs/f1884b46-ecb4-473c-81f5-08d9bf2ab3bb");
+ it("Should be able to access '/jobDetails/:id' directly", () => {
+ cy.visit("http://localhost:3000/jobDetails/f1884b46-ecb4-473c-81f5-08d9bf2ab3bb");
cy.wait(500);
cy.get("h2").should("have.text", "Cloud DevOps Engineer");
diff --git a/cypress/integration/hiddenJobs.spec.js b/cypress/integration/hiddenJobs.spec.js
index fc83232..4ff92f8 100644
--- a/cypress/integration/hiddenJobs.spec.js
+++ b/cypress/integration/hiddenJobs.spec.js
@@ -4,20 +4,29 @@ context("Hidden Jobs", () => {
beforeEach(() => {
cy.fixture("jobs50").then((jobsJson) => {
cy.fixture("hiddenDetails").then((hiddenDetailsJson) => {
- cy.server();
- cy.route({
- method: "GET",
- url: "/jobs",
- status: 200,
- response: jobsJson,
- delay: 1000,
- });
- cy.route({
- method: "GET",
- url: "/user/hiddenJobsDetails",
- status: 200,
- response: hiddenDetailsJson,
- delay: 1000,
+ cy.fixture("jobDetails").then((jobDetailsJson) => {
+ cy.server();
+ cy.route({
+ method: "POST",
+ url: "/jobs",
+ status: 200,
+ response: jobsJson,
+ delay: 1000,
+ });
+ cy.route({
+ method: "GET",
+ url: "/user/hiddenJobsDetails",
+ status: 200,
+ response: hiddenDetailsJson,
+ delay: 1000,
+ });
+ cy.route({
+ method: "GET",
+ url: "/jobs/f1884b46-ecb4-473c-81f5-08d9bf2ab3bb",
+ status: 200,
+ response: jobDetailsJson,
+ delay: 1000,
+ });
});
});
});
@@ -223,6 +232,29 @@ context("Hidden Jobs", () => {
cy.get("#show-job-72de09f2-5bc6-489f-be90-3d38e505e20a").click();
cy.get("#show-job-cc20d9f2-0102-4785-8253-66093d3ca5c0").click();
});
+
+ // ! Unable to do with current implementation
+ // * If you don't stub it, the real db may not contain that job listing anymore
+ // * If you do stub it, you can't conditionally send a smaller list of jobs each time it hits /user/hiddenJobDetails
+ it.skip("Should not display hidden jobs in currentJobs", () => {
+ // * Hide a job
+ cy.get("#hide-job-f1884b46-ecb4-473c-81f5-08d9bf2ab3bb").click();
+ // * Log User out
+ cy.get("#nav-profile").click();
+ cy.get("#settings").click();
+ cy.get("#log-out").click();
+
+ cy.get("#f1884b46-ecb4-473c-81f5-08d9bf2ab3bb").should("exist");
+
+ // * Log In
+ cy.get("#nav-login").click();
+ cy.get("#email").type("bobtest@email.com");
+ cy.get("#password").type("Red123456!!!");
+ cy.get("#log-in").click();
+ cy.wait(500);
+
+ cy.get("#f1884b46-ecb4-473c-81f5-08d9bf2ab3bb").should("not.exist");
+ });
});
context("Hidden Jobs - No Results", () => {
@@ -230,7 +262,7 @@ context("Hidden Jobs - No Results", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -254,7 +286,7 @@ context("Hidden Jobs - No Results", () => {
cy.get("#nav-profile").click();
cy.get("#view-hidden-jobs").click();
- assert.equal(cy.state("requests").length, 3);
+ assert.equal(cy.state("requests").length, 4);
});
it("Should display correct text", () => {
diff --git a/cypress/integration/login.spec.js b/cypress/integration/login.spec.js
index fae6a31..50901bb 100644
--- a/cypress/integration/login.spec.js
+++ b/cypress/integration/login.spec.js
@@ -6,7 +6,7 @@ context("Login - Success", () => {
cy.fixture("login").then((loginJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -48,7 +48,7 @@ context("Login - Error", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/cypress/integration/notification.spec.js b/cypress/integration/notification.spec.js
index 9405d86..599b8f6 100644
--- a/cypress/integration/notification.spec.js
+++ b/cypress/integration/notification.spec.js
@@ -5,7 +5,7 @@ context("Notification", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/cypress/integration/optionsPanel.spec.js b/cypress/integration/optionsPanel.spec.js
index 3d60ecb..2f253cb 100644
--- a/cypress/integration/optionsPanel.spec.js
+++ b/cypress/integration/optionsPanel.spec.js
@@ -8,7 +8,7 @@ context("Options Panel", () => {
cy.fixture("jobsSearch3").then((jobsSearch3Json) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -16,7 +16,7 @@ context("Options Panel", () => {
cy.route({
method: "GET",
url:
- "/jobs/search?full_time=true&contract=false&description=developer",
+ "/jobs/search?userId=&full_time=true&contract=false&description=developer",
status: 200,
delay: 1000,
response: jobsSearch2Json,
@@ -24,7 +24,7 @@ context("Options Panel", () => {
cy.route({
method: "GET",
url:
- "/jobs/search?full_time=false&contract=false&description=&location1=Los Angeles",
+ "/jobs/search?userId=&full_time=false&contract=false&description=&location1=Los Angeles",
status: 200,
delay: 1000,
response: jobsSearch1Json,
@@ -32,7 +32,7 @@ context("Options Panel", () => {
cy.route({
method: "GET",
url:
- "/jobs/search?full_time=false&contract=false&description=&location1=Chicago",
+ "/jobs/search?userId=&full_time=false&contract=false&description=&location1=Chicago",
status: 200,
delay: 1000,
response: jobsSearch1Json,
@@ -40,7 +40,7 @@ context("Options Panel", () => {
cy.route({
method: "GET",
url:
- "/jobs/search?full_time=false&contract=false&description=developer",
+ "/jobs/search?userId=&full_time=false&contract=false&description=developer",
status: 200,
delay: 1000,
response: jobsSearch1Json,
@@ -48,7 +48,7 @@ context("Options Panel", () => {
cy.route({
method: "GET",
url:
- "/jobs/search?full_time=false&contract=false&description=&location1=Los Angeles",
+ "/jobs/search?userId=&full_time=false&contract=false&description=&location1=Los Angeles",
status: 200,
delay: 1000,
response: jobsSearch1Json,
@@ -56,7 +56,7 @@ context("Options Panel", () => {
cy.route({
method: "GET",
url:
- "/jobs/search?full_time=false&contract=true&description=developer",
+ "/jobs/search?userId=&full_time=false&contract=true&description=developer",
status: 200,
delay: 1000,
response: jobsSearch3Json,
diff --git a/cypress/integration/pagination.spec.js b/cypress/integration/pagination.spec.js
index 71f7856..fb1c734 100644
--- a/cypress/integration/pagination.spec.js
+++ b/cypress/integration/pagination.spec.js
@@ -5,7 +5,7 @@ context("Pagination", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -213,7 +213,7 @@ context("Pagination", () => {
cy.server();
cy.route({
method: "GET",
- url: "/jobs/search?full_time=false&contract=false&description=&location1=Chicago",
+ url: "/jobs/search?userId=&full_time=false&contract=false&description=&location1=Chicago",
status: 200,
response: jobsJson,
});
@@ -258,7 +258,7 @@ context("Pagination - 1 Page", () => {
cy.fixture("jobs5").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -296,7 +296,7 @@ context("Pagination - 2 Pages", () => {
cy.fixture("jobs10").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -334,7 +334,7 @@ context("Pagination - 3 Pages", () => {
cy.fixture("jobs15").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -374,7 +374,7 @@ context("Pagination - 4 Pages", () => {
cy.fixture("jobs20").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/cypress/integration/profile.spec.js b/cypress/integration/profile.spec.js
index 145fe49..ec6eec3 100644
--- a/cypress/integration/profile.spec.js
+++ b/cypress/integration/profile.spec.js
@@ -5,7 +5,7 @@ context("Profile", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/cypress/integration/savedJobs.spec.js b/cypress/integration/savedJobs.spec.js
index a31070a..108147e 100644
--- a/cypress/integration/savedJobs.spec.js
+++ b/cypress/integration/savedJobs.spec.js
@@ -4,20 +4,29 @@ context("Saved Jobs", () => {
beforeEach(() => {
cy.fixture("jobs50").then((jobsJson) => {
cy.fixture("savedDetails").then((savedDetailsJson) => {
- cy.server();
- cy.route({
- method: "GET",
- url: "/jobs",
- status: 200,
- response: jobsJson,
- delay: 1000,
- });
- cy.route({
- method: "GET",
- url: "/user/savedJobsDetails",
- status: 200,
- response: savedDetailsJson,
- delay: 1000,
+ cy.fixture("jobDetails").then((jobDetailsJson) => {
+ cy.server();
+ cy.route({
+ method: "POST",
+ url: "/jobs",
+ status: 200,
+ response: jobsJson,
+ delay: 1000,
+ });
+ cy.route({
+ method: "GET",
+ url: "/user/savedJobsDetails",
+ status: 200,
+ response: savedDetailsJson,
+ delay: 1000,
+ });
+ cy.route({
+ method: "GET",
+ url: "/jobs/f1884b46-ecb4-473c-81f5-08d9bf2ab3bb",
+ status: 200,
+ response: jobDetailsJson,
+ delay: 1000,
+ });
});
});
});
@@ -145,7 +154,7 @@ context("Saved Jobs - No Results", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -169,7 +178,7 @@ context("Saved Jobs - No Results", () => {
cy.get("#nav-profile").click();
cy.get("#view-saved-jobs").click();
- assert.equal(cy.state("requests").length, 3);
+ assert.equal(cy.state("requests").length, 4);
});
it("Should display correct text", () => {
diff --git a/cypress/integration/search.spec.js b/cypress/integration/search.spec.js
index 5ef1957..9ed1673 100644
--- a/cypress/integration/search.spec.js
+++ b/cypress/integration/search.spec.js
@@ -6,7 +6,7 @@ context("Search", () => {
cy.fixture("jobsSearch1").then((searchJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -14,7 +14,8 @@ context("Search", () => {
});
cy.route({
method: "GET",
- url: "/jobs/search?full_time=false&contract=false&description=developer",
+ url:
+ "/jobs/search?userId=&full_time=false&contract=false&description=developer",
status: 200,
response: searchJson,
delay: 1000,
@@ -50,13 +51,38 @@ context("Search", () => {
cy.get("#search").type("{enter}");
cy.get('[data-cy="orbit-container"]').should("be.visible");
});
+
+ // ! Unable to do with current implementation
+ // * If you don't stub it, the real db may not contain that job listing anymore
+ // * If you do stub it, you can't conditionally send a smaller list of jobs each time it hits /user/hiddenJobDetails
+ it.skip("Should not display hidden jobs in currentJobs on search", () => {
+ // * Hide a job
+ cy.get("#hide-job-f1884b46-ecb4-473c-81f5-08d9bf2ab3bb").click();
+ // * Log User out
+ cy.get("#nav-profile").click();
+ cy.get("#settings").click();
+ cy.get("#log-out").click();
+
+ cy.get("#f1884b46-ecb4-473c-81f5-08d9bf2ab3bb").should("exist");
+
+ // * Log In
+ cy.get("#nav-login").click();
+ cy.get("#email").type("bobtest@email.com");
+ cy.get("#password").type("Red123456!!!");
+ cy.get("#log-in").click();
+ cy.wait(500);
+
+ cy.get("#f1884b46-ecb4-473c-81f5-08d9bf2ab3bb").should("not.exist");
+
+ // * Do search
+ });
});
context("Search - No Results", () => {
beforeEach(() => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: [],
@@ -64,7 +90,8 @@ context("Search - No Results", () => {
});
cy.route({
method: "GET",
- url: "/jobs/search?full_time=false&contract=false&description=developer",
+ url:
+ "/jobs/search?userId=&full_time=false&contract=false&description=developer",
status: 200,
response: [],
delay: 1000,
@@ -88,7 +115,7 @@ context("Search - Loading Indicator", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/cypress/integration/signup.spec.js b/cypress/integration/signup.spec.js
index 88de989..0d7e931 100644
--- a/cypress/integration/signup.spec.js
+++ b/cypress/integration/signup.spec.js
@@ -6,7 +6,7 @@ context("Signup - Success", () => {
cy.fixture("signup").then((signupJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
@@ -53,7 +53,7 @@ context("Signup - Error", () => {
cy.fixture("jobs50").then((jobsJson) => {
cy.server();
cy.route({
- method: "GET",
+ method: "POST",
url: "/jobs",
status: 200,
response: jobsJson,
diff --git a/package-lock.json b/package-lock.json
index 6c16623..70cfa7d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "gh-jobs",
- "version": "1.5.0",
+ "version": "1.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 08d0bcd..0818518 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gh-jobs",
- "version": "1.5.0",
+ "version": "1.6.0",
"description": "A MERN application bootstrapped with create-mern-application.",
"main": "build/index.js",
"scripts": {
diff --git a/src/client/App.tsx b/src/client/App.tsx
index ad67819..12c4c81 100644
--- a/src/client/App.tsx
+++ b/src/client/App.tsx
@@ -56,7 +56,7 @@ const App: React.SFC = (props: AppProps) => {
-
+
diff --git a/src/client/components/JobCard/JobCard.tsx b/src/client/components/JobCard/JobCard.tsx
index a2409f9..8c199f6 100644
--- a/src/client/components/JobCard/JobCard.tsx
+++ b/src/client/components/JobCard/JobCard.tsx
@@ -91,7 +91,7 @@ const JobCard: React.SFC = (props: JobCardProps) => {
handleClearJobDetails()}
- to={`/jobs/${job.id}`}
+ to={`/jobDetails/${job.id}`}
>
{job.title}
diff --git a/src/client/components/Profile/Profile-styled.tsx b/src/client/components/Profile/Profile-styled.tsx
index ba2d6f7..11bd5ee 100644
--- a/src/client/components/Profile/Profile-styled.tsx
+++ b/src/client/components/Profile/Profile-styled.tsx
@@ -84,7 +84,7 @@ const ProfileAccountStatsContainer = styled.div`
@media only screen and (max-width: 820px) {
margin-bottom: 50px;
margin-top: 100px;
- width: 100%;
+ width: auto;
}
`;
diff --git a/src/client/redux/actionTypes.ts b/src/client/redux/actionTypes.ts
index 7858d86..eba082d 100644
--- a/src/client/redux/actionTypes.ts
+++ b/src/client/redux/actionTypes.ts
@@ -24,6 +24,7 @@ export const SET_EDIT_NAME = "SET_EDIT_NAME";
export const SET_EMAIL = "SET_EMAIL";
export const SET_HIDDEN_JOBS = "SET_HIDDEN_JOBS";
export const SET_HIDDEN_JOBS_DETAILS = "SET_HIDDEN_JOBS_DETAILS";
+export const SET_ID = "SET_ID";
export const SET_IS_EDITING_PROFILE = "SET_IS_EDITING_PROFILE";
export const SET_IS_LOGGED_IN = "SET_IS_LOGGED_IN";
export const SET_NAME = "SET_NAME";
diff --git a/src/client/redux/actions/user.ts b/src/client/redux/actions/user.ts
index 75ae5f8..979abdd 100644
--- a/src/client/redux/actions/user.ts
+++ b/src/client/redux/actions/user.ts
@@ -3,6 +3,7 @@ import {
SET_EMAIL,
SET_HIDDEN_JOBS,
SET_HIDDEN_JOBS_DETAILS,
+ SET_ID,
SET_IS_EDITING_PROFILE,
SET_IS_LOGGED_IN,
SET_NAME,
@@ -38,6 +39,11 @@ export const setHiddenJobsDetails = (hiddenJobsDetails: Job[]): UserAction => ({
payload: { hiddenJobsDetails },
});
+export const setId = (id: string): UserAction => ({
+ type: SET_ID,
+ payload: { id },
+});
+
export const setIsEditingProfile = (isEditingProfile: boolean): UserAction => ({
type: SET_IS_EDITING_PROFILE,
payload: { isEditingProfile },
diff --git a/src/client/redux/reducers/user.ts b/src/client/redux/reducers/user.ts
index 5911427..92cd3cb 100644
--- a/src/client/redux/reducers/user.ts
+++ b/src/client/redux/reducers/user.ts
@@ -3,6 +3,7 @@ import {
SET_EMAIL,
SET_HIDDEN_JOBS,
SET_HIDDEN_JOBS_DETAILS,
+ SET_ID,
SET_IS_EDITING_PROFILE,
SET_IS_LOGGED_IN,
SET_NAME,
@@ -23,6 +24,7 @@ export const initialState: UserState = {
email: "",
hiddenJobs: [],
hiddenJobsDetails: [],
+ id: "",
isEditingProfile: false,
isLoggedIn: false,
name: "",
@@ -50,6 +52,7 @@ const reducer = (state = initialState, action: UserAction): UserState => {
case SET_EMAIL:
case SET_HIDDEN_JOBS:
case SET_HIDDEN_JOBS_DETAILS:
+ case SET_ID:
case SET_IS_EDITING_PROFILE:
case SET_IS_LOGGED_IN:
case SET_NAME:
diff --git a/src/client/redux/thunks.ts b/src/client/redux/thunks.ts
index ecd127f..9b4fe89 100644
--- a/src/client/redux/thunks.ts
+++ b/src/client/redux/thunks.ts
@@ -30,34 +30,28 @@ import {
setSavedJobsTotalPages,
setHiddenJobs,
setHiddenJobsDetails,
+ setId,
} from "./actions/user";
import { fetchServerData, isError } from "../util";
import {
- AddHiddenJobErrorResponse,
AddHiddenJobSuccessResponse,
- AddSavedJobErrorResponse,
AddSavedJobSuccessResponse,
AppThunk,
DeleteProfileResponse,
EditProfileResponse,
- GetHiddenJobsDetailsErrorResponse,
+ ErrorResponse,
GetHiddenJobsDetailsSuccessResponse,
- GetJobsErrorResponse,
GetJobsSuccessResponse,
- GetSavedJobsDetailsErrorResponse,
GetSavedJobsDetailsSuccessResponse,
Job,
LocationOption,
LoginResponse,
- RemoveHiddenJobErrorResponse,
RemoveHiddenJobSuccessResponse,
- RemoveSavedJobErrorResponse,
RemoveSavedJobSuccessResponse,
ResetPasswordResponse,
RootState,
ServerResponseUser,
- SignupErrorResponse,
SignupSuccessResponse,
} from "../types";
@@ -71,6 +65,7 @@ export const searchJobs = (
const state: RootState = getState();
const { contract, fullTime, locationSearch } = state.application;
+ const { id } = state.user;
const locationsSearches = locationOptions.filter(
(location: LocationOption) => location.value !== ""
@@ -84,7 +79,7 @@ export const searchJobs = (
});
}
- let url = `/jobs/search?full_time=${encodeURI(
+ let url = `/jobs/search?userId=${encodeURI(id)}&full_time=${encodeURI(
fullTime.toString()
)}&contract=${encodeURI(contract.toString())}&description=${encodeURI(
search
@@ -95,7 +90,7 @@ export const searchJobs = (
});
const data = (await fetchServerData(url, "GET")) as
- | GetJobsErrorResponse
+ | ErrorResponse
| GetJobsSuccessResponse;
if (isError(data)) {
@@ -137,9 +132,25 @@ export const logIn = (): AppThunk => async (dispatch, getState) => {
return;
}
+ // * Establish Job Data
+ const jobsResult = (await fetchServerData(
+ "/jobs",
+ "POST",
+ JSON.stringify({ userId: response._id })
+ )) as ErrorResponse | GetJobsSuccessResponse;
+
+ if (isError(jobsResult)) {
+ dispatch(displayNotification(jobsResult.error, "error"));
+ dispatch(setIsLoading(false));
+ return;
+ }
+
dispatch(setIsLoggedIn(true));
+ dispatch(setCurrentJobs(jobsResult));
+ dispatch(setTotalPages(Math.ceil(jobsResult.length / 5)));
dispatch(setEmail(response.email));
dispatch(setName(response.name));
+ dispatch(setId(response._id));
dispatch(setSavedJobs(response.savedJobs));
dispatch(setHiddenJobs(response.hiddenJobs));
@@ -160,9 +171,7 @@ export const signup = (): AppThunk => async (dispatch, getState) => {
}
// TODO - Modify
- const result:
- | SignupErrorResponse
- | SignupSuccessResponse = await fetchServerData(
+ const result: ErrorResponse | SignupSuccessResponse = await fetchServerData(
"/user",
"POST",
JSON.stringify({ confirmPassword, email, name, password })
@@ -188,6 +197,8 @@ export const signup = (): AppThunk => async (dispatch, getState) => {
export const initializeApplication = (): AppThunk => async (dispatch) => {
try {
dispatch(setIsLoading(true));
+
+ // * Reset State to Defaults
dispatch(displayNotification("", "default"));
dispatch(setError(null, null));
dispatch(setCurrentJobs([]));
@@ -199,42 +210,41 @@ export const initializeApplication = (): AppThunk => async (dispatch) => {
dispatch(setModalContent(""));
dispatch(setModalTitle(""));
- // * Establish Job Data
- dispatch(setIsLoading(true));
-
- const jobsResult = (await fetchServerData("/jobs", "GET")) as
- | GetJobsErrorResponse
- | GetJobsSuccessResponse;
-
- if (isError(jobsResult)) {
- dispatch(displayNotification(jobsResult.error, "error"));
- dispatch(setIsLoading(false));
- return;
- }
-
- dispatch(setJobs(jobsResult));
- dispatch(setCurrentPage(1));
- dispatch(setTotalPages(Math.ceil(jobsResult.length / 5)));
- dispatch(setCurrentJobs(jobsResult));
-
// * Establish User Authentication
const userResponse = await fetch("/user/me");
+ let userId = "";
if (userResponse.status === 200) {
+ // * User is authenticated
const user: ServerResponseUser = await userResponse.json();
- const nonHiddenJobs = jobsResult.filter(
- (job: Job) => user.hiddenJobs.indexOf(job.id) < 0
- );
+ userId = user._id;
dispatch(setName(user.name));
dispatch(setEmail(user.email));
+ dispatch(setId(userId));
dispatch(setSavedJobs(user.savedJobs));
dispatch(setHiddenJobs(user.hiddenJobs));
dispatch(setIsLoggedIn(true));
- dispatch(setCurrentJobs(nonHiddenJobs));
- dispatch(setTotalPages(Math.ceil(nonHiddenJobs.length / 5)));
}
+
+ // * Establish Job Data
+ const jobsResult = (await fetchServerData(
+ "/jobs",
+ "POST",
+ JSON.stringify({ userId })
+ )) as ErrorResponse | GetJobsSuccessResponse;
+
+ if (isError(jobsResult)) {
+ dispatch(displayNotification(jobsResult.error, "error"));
+ dispatch(setIsLoading(false));
+ return;
+ }
+
+ dispatch(setJobs(jobsResult));
+ dispatch(setCurrentPage(1));
+ dispatch(setTotalPages(Math.ceil(jobsResult.length / 5)));
+ dispatch(setCurrentJobs(jobsResult));
dispatch(setIsLoading(false));
} catch (error) {
console.error(error);
@@ -259,10 +269,26 @@ export const logOut = (): AppThunk => async (dispatch) => {
return;
}
+ // * Establish Job Data
+ const jobsResult = (await fetchServerData(
+ "/jobs",
+ "POST",
+ JSON.stringify({ userId: "" })
+ )) as ErrorResponse | GetJobsSuccessResponse;
+
+ if (isError(jobsResult)) {
+ dispatch(displayNotification(jobsResult.error, "error"));
+ dispatch(setIsLoading(false));
+ return;
+ }
+
+ dispatch(displayNotification("", "default"));
+ dispatch(setCurrentJobs(jobsResult));
+ dispatch(setTotalPages(Math.ceil(jobsResult.length / 5)));
dispatch(setConfirmPassword(""));
dispatch(setEmail(""));
- dispatch(displayNotification("", "default"));
dispatch(setName(""));
+ dispatch(setId(""));
dispatch(setPassword(""));
dispatch(setSavedJobs([]));
dispatch(setHiddenJobs([]));
@@ -290,10 +316,26 @@ export const logOutAll = (): AppThunk => async (dispatch) => {
return;
}
+ // * Establish Job Data
+ const jobsResult = (await fetchServerData(
+ "/jobs",
+ "POST",
+ JSON.stringify({ userId: "" })
+ )) as ErrorResponse | GetJobsSuccessResponse;
+
+ if (isError(jobsResult)) {
+ dispatch(displayNotification(jobsResult.error, "error"));
+ dispatch(setIsLoading(false));
+ return;
+ }
+
dispatch(setConfirmPassword(""));
- dispatch(setEmail(""));
dispatch(displayNotification("", "default"));
+ dispatch(setCurrentJobs(jobsResult));
+ dispatch(setTotalPages(Math.ceil(jobsResult.length / 5)));
+ dispatch(setEmail(""));
dispatch(setName(""));
+ dispatch(setId(""));
dispatch(setPassword(""));
dispatch(setSavedJobs([]));
dispatch(setHiddenJobs([]));
@@ -425,7 +467,7 @@ export const addHiddenJob = (id: string): AppThunk => async (
const { currentJobs } = state.application;
// TODO - Modify
const result:
- | AddHiddenJobErrorResponse
+ | ErrorResponse
| AddHiddenJobSuccessResponse = await fetchServerData(
"/user/hiddenJobs",
"PATCH",
@@ -459,7 +501,7 @@ export const addSavedJob = (id: string): AppThunk => async (dispatch) => {
try {
// TODO - Modify
const result:
- | AddSavedJobErrorResponse
+ | ErrorResponse
| AddSavedJobSuccessResponse = await fetchServerData(
"/user/savedJobs",
"PATCH",
@@ -491,7 +533,7 @@ export const removeHiddenJob = (id: string): AppThunk => async (dispatch) => {
try {
// TODO - Modify
const result:
- | RemoveHiddenJobErrorResponse
+ | ErrorResponse
| RemoveHiddenJobSuccessResponse = await fetchServerData(
"/user/hiddenJobs",
"PATCH",
@@ -521,7 +563,7 @@ export const removeSavedJob = (id: string): AppThunk => async (dispatch) => {
try {
// TODO - Modify
const result:
- | RemoveSavedJobErrorResponse
+ | ErrorResponse
| RemoveSavedJobSuccessResponse = await fetchServerData(
"/user/savedJobs",
"PATCH",
@@ -592,7 +634,7 @@ export const getSavedJobsDetails = (): AppThunk => async (dispatch) => {
try {
const result:
- | GetSavedJobsDetailsErrorResponse
+ | ErrorResponse
| GetSavedJobsDetailsSuccessResponse = await fetchServerData(
`/user/savedJobsDetails`,
"GET"
@@ -619,7 +661,7 @@ export const getHiddenJobsDetails = (): AppThunk => async (dispatch) => {
try {
const result:
- | GetHiddenJobsDetailsErrorResponse
+ | ErrorResponse
| GetHiddenJobsDetailsSuccessResponse = await fetchServerData(
`/user/hiddenJobsDetails`,
"GET"
diff --git a/src/client/types.ts b/src/client/types.ts
index dcd3753..f967c28 100644
--- a/src/client/types.ts
+++ b/src/client/types.ts
@@ -1,10 +1,6 @@
import { Action } from "redux";
import { ThunkAction } from "redux-thunk";
-export interface AddHiddenJobErrorResponse {
- error: string;
-}
-
export interface AddHiddenJobSuccessResponse {
createdAt: string;
email: string;
@@ -16,10 +12,6 @@ export interface AddHiddenJobSuccessResponse {
_id: string;
}
-export interface AddSavedJobErrorResponse {
- error: string;
-}
-
export interface AddSavedJobSuccessResponse {
createdAt: string;
email: string;
@@ -69,32 +61,20 @@ export type ButtonStyle = "primary" | "secondary" | "danger";
export type ButtonType = "button" | "reset" | "submit";
-export type DeleteProfileResponse = ServerResponseError & ServerResponseUser;
+export type DeleteProfileResponse = ErrorResponse & ServerResponseUser;
-export type EditProfileResponse = ServerResponseError & ServerResponseUser;
+export type EditProfileResponse = ErrorResponse & ServerResponseUser;
-export interface GetJobDetailsErrorResponse {
+export interface ErrorResponse {
error: string;
}
export type GetJobDetailsSuccessResponse = Job;
-export interface GetJobsErrorResponse {
- error: string;
-}
-
export type GetJobsSuccessResponse = Job[];
-export interface GetHiddenJobsDetailsErrorResponse {
- error: string;
-}
-
export type GetHiddenJobsDetailsSuccessResponse = Job[];
-export interface GetSavedJobsDetailsErrorResponse {
- error: string;
-}
-
export type GetSavedJobsDetailsSuccessResponse = Job[];
export type InputAutoComplete =
@@ -188,7 +168,7 @@ export interface LocationOption {
value: string;
}
-export type LoginResponse = ServerResponseError & ServerResponseUser;
+export type LoginResponse = ErrorResponse & ServerResponseUser;
export interface ModalAction {
type: string;
@@ -212,10 +192,6 @@ export type NotificationType =
export type PaginationNavigationType = "left" | "right";
-export interface RemoveHiddenJobErrorResponse {
- error: string;
-}
-
export interface RemoveHiddenJobSuccessResponse {
createdAt: string;
email: string;
@@ -227,10 +203,6 @@ export interface RemoveHiddenJobSuccessResponse {
_id: string;
}
-export interface RemoveSavedJobErrorResponse {
- error: string;
-}
-
export interface RemoveSavedJobSuccessResponse {
createdAt: string;
email: string;
@@ -244,7 +216,7 @@ export interface RemoveSavedJobSuccessResponse {
export type RequestMethod = "DELETE" | "GET" | "PATCH" | "POST";
-export type ResetPasswordResponse = ServerResponseError & ServerResponseUser;
+export type ResetPasswordResponse = ErrorResponse & ServerResponseUser;
export type RootState = {
application: ApplicationState;
@@ -254,10 +226,6 @@ export type RootState = {
export type SearchType = "description" | "location";
-export interface ServerResponseError {
- error: string;
-}
-
export interface ServerResponseUser {
createdAt: string;
email: string;
@@ -269,10 +237,6 @@ export interface ServerResponseUser {
_id: string;
}
-export interface SignupErrorResponse {
- error: string;
-}
-
export interface SignupSuccessResponse {
createdAt: string;
email: string;
@@ -295,6 +259,7 @@ export interface UserState {
email: string;
hiddenJobs: string[];
hiddenJobsDetails: Job[];
+ id: string;
isEditingProfile: boolean;
isLoggedIn: false;
name: string;
diff --git a/src/client/util.ts b/src/client/util.ts
index 9db4e22..cf88855 100644
--- a/src/client/util.ts
+++ b/src/client/util.ts
@@ -1,14 +1,11 @@
import { createBrowserHistory } from "history";
import {
+ ErrorResponse,
RequestMethod,
- GetJobDetailsErrorResponse,
GetJobDetailsSuccessResponse,
- GetJobsErrorResponse,
GetJobsSuccessResponse,
- AddSavedJobErrorResponse,
AddSavedJobSuccessResponse,
- SignupErrorResponse,
SignupSuccessResponse,
} from "./types";
@@ -30,32 +27,6 @@ export const fetchServerData = async (
return data;
};
-// TODO - Remove
-// eslint-disable-next-line
-export const groupBy = (arr: any[], key: any): any =>
- arr.reduce(
- (acc, item) => ((acc[item[key]] = [...(acc[item[key]] || []), item]), acc),
- {}
- );
-
-// TODO - Remove
-// eslint-disable-next-line
-export const unique = (arr: any[]): any[] => [...new Set(arr)];
-
-// TODO - Remove
-export const validURL = (str: string): boolean => {
- const pattern = new RegExp(
- "^(https?:\\/\\/)?" + // protocol
- "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
- "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
- "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
- "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
- "(\\#[-a-z\\d_]*)?$",
- "i"
- ); // fragment locator
- return !!pattern.test(str);
-};
-
/**
* Loads the state of the application from localStorage if present.
* @returns {object}
@@ -89,16 +60,13 @@ export const saveState = (state: any): void => {
export const isError = (
result:
- | GetJobsErrorResponse
- | GetJobsSuccessResponse
- | GetJobDetailsErrorResponse
- | GetJobDetailsSuccessResponse
- | AddSavedJobErrorResponse
| AddSavedJobSuccessResponse
- | SignupErrorResponse
+ | ErrorResponse
+ | GetJobDetailsSuccessResponse
+ | GetJobsSuccessResponse
| SignupSuccessResponse
-): result is GetJobsErrorResponse => {
- return (result as GetJobsErrorResponse).error !== undefined;
+): result is ErrorResponse => {
+ return (result as ErrorResponse).error !== undefined;
};
export const history = createBrowserHistory();
diff --git a/src/server/app.ts b/src/server/app.ts
index 4062a38..8c10af4 100644
--- a/src/server/app.ts
+++ b/src/server/app.ts
@@ -85,10 +85,16 @@ class App {
// ? Use this.app.all?
console.log(
- chalk.blueBright.inverse({
- host: req.headers.host,
- referrer: req.headers.referer,
- })
+ chalk.blueBright.inverse(
+ JSON.stringify(
+ {
+ host: req.headers.host,
+ referrer: req.headers.referer,
+ },
+ null,
+ 2
+ )
+ )
);
res.sendFile(path.join(__dirname, "../dist/index.html"));
});
diff --git a/src/server/controllers/job.ts b/src/server/controllers/job.ts
index 0ef0e37..073a76d 100644
--- a/src/server/controllers/job.ts
+++ b/src/server/controllers/job.ts
@@ -7,16 +7,16 @@ import path from "path";
import JobModel from "../models/Job";
-import { getAllJobsFromAPI, isError, unique } from "../util";
+import { unique, rehydrateJobsDB } from "../util";
import {
- GetJobsErrorResponse,
+ ErrorResponse,
GetJobsSuccessResponse,
Job,
- GetJobDetailsErrorResponse,
GetJobDetailsSuccessResponse,
- GitHubJob,
+ JobDocument,
} from "../types";
+import User from "../models/User";
/**
* Job Controller.
@@ -29,40 +29,39 @@ class JobController {
}
public initializeRoutes(): void {
- this.router.get(
+ this.router.post(
"/jobs",
async (
req: Request,
res: Response
- ): Promise> => {
+ ): Promise> => {
try {
- const currentJobs = await JobModel.find({});
+ // * Get User Information
+ const userId: string = req.body.userId;
+ let user = null;
+ let hiddenJobs: string[] = [];
+ if (userId !== "") {
+ user = await User.findById(userId);
+ hiddenJobs = user.hiddenJobs;
+ }
+
+ // * Get Job Information
+ let dbJobs: JobDocument[] = await JobModel.find({});
// * No Jobs exist in DB
- if (currentJobs.length === 0) {
- const result = await getAllJobsFromAPI();
+ if (dbJobs.length === 0) {
+ const rehydrationResult = await rehydrateJobsDB();
- if (isError(result)) {
- return res.status(500).send(result);
+ // TODO - Check for this in a different way
+ if (rehydrationResult !== true) {
+ return res.status(500).send(rehydrationResult);
}
- await Promise.all(
- result.map(async (job: GitHubJob) => {
- const newJobObject: Job = {
- ...job,
- listingDate: job.created_at,
- };
- const newJob = new JobModel(newJobObject);
- await newJob.save();
- return;
- })
- );
-
- const dbJobs = await JobModel.find({});
- return res.send(dbJobs);
+ // * Set dbJobs to new jobs
+ dbJobs = await JobModel.find({});
} else {
- // * Jobs exist in DB
- const { createdAt } = currentJobs[0];
+ // * Jobs exist in DB, but we need to ensure they are not stale jobs (from yesterday)
+ const { createdAt } = dbJobs[0];
const isWithinToday = isWithinInterval(new Date(createdAt), {
start: startOfToday(),
@@ -71,35 +70,24 @@ class JobController {
if (!isWithinToday) {
// * Jobs are stale. Get new jobs.
- const result = await getAllJobsFromAPI();
+ const rehydration2Result = await rehydrateJobsDB();
- if (isError(result)) {
- return res.status(500).send(result);
+ // TODO - Check for this in a different way
+ if (rehydration2Result !== true) {
+ return res.status(500).send(rehydration2Result);
}
- // * Drop the current database of Jobs
- await JobModel.collection.drop();
-
- // * Create new Job entries
- await Promise.all(
- result.map(async (job: GitHubJob) => {
- const newJobObject: Job = {
- ...job,
- listingDate: job.created_at,
- };
- const newJob = new JobModel(newJobObject);
- await newJob.save();
- return;
- })
- );
-
- const dbJobs = await JobModel.find({});
- return res.send(dbJobs);
- } else {
- // * Jobs are fine, send that.
- return res.send(currentJobs);
+ // * Set dbJobs to new jobs
+ dbJobs = await JobModel.find({});
}
}
+
+ // * Ensure that the user's hiddenJobs do not show in results
+ const filteredDBJobs: JobDocument[] = dbJobs.filter(
+ (jobDocument: JobDocument) => hiddenJobs.indexOf(jobDocument.id) < 0
+ );
+
+ return res.send(filteredDBJobs);
} catch (error) {
if (process.env.NODE_ENV !== "test") {
console.error(error);
@@ -115,7 +103,7 @@ class JobController {
async (
req: Request,
res: Response
- ): Promise> => {
+ ): Promise> => {
try {
const {
contract,
@@ -126,6 +114,7 @@ class JobController {
location3,
location4,
location5,
+ userId,
} = req.query;
const isLocationSearch =
@@ -170,8 +159,19 @@ class JobController {
);
const uniqueResults: Job[] = unique(jobs);
+ let finalResults = uniqueResults;
+
+ // * Filter by non-hidden jobs
+ if (userId) {
+ // * Get User Information
+ const user = await User.findById(userId);
+ const hiddenJobs: string[] = user.hiddenJobs;
+ finalResults = uniqueResults.filter(
+ (job: Job) => hiddenJobs.indexOf(job.id) < 0
+ );
+ }
- return res.send(uniqueResults);
+ return res.send(finalResults);
}
// * Make Searches
@@ -203,8 +203,19 @@ class JobController {
];
const uniqueResults: Job[] = unique(searchResults);
+ let finalResults = uniqueResults;
+
+ // * Filter by non-hidden jobs
+ if (userId) {
+ // * Get User Information
+ const user = await User.findById(userId);
+ const hiddenJobs: string[] = user.hiddenJobs;
+ finalResults = uniqueResults.filter(
+ (job: Job) => hiddenJobs.indexOf(job.id) < 0
+ );
+ }
- return res.send(uniqueResults);
+ return res.send(finalResults);
} catch (error) {
if (process.env.NODE_ENV !== "test") {
console.error(error);
@@ -220,7 +231,7 @@ class JobController {
req: Request,
res: Response
): Promise | void> => {
if (!req.headers.referer) {
return res.sendFile(path.join(__dirname, "../../dist/index.html"));
diff --git a/src/server/controllers/user.ts b/src/server/controllers/user.ts
index e4e006d..2218e66 100644
--- a/src/server/controllers/user.ts
+++ b/src/server/controllers/user.ts
@@ -12,15 +12,13 @@ import {
AuthenticatedRequest,
EditHiddenJobsMethod,
EditSavedJobsMethod,
- GetHiddenJobsDetailsErrorResponse,
+ ErrorResponse,
GetHiddenJobsDetailsSuccessResponse,
- GetSavedJobsDetailsErrorResponse,
GetSavedJobsDetailsSuccessResponse,
- PatchSavedJobErrorResponse,
+ Job,
PatchSavedJobSuccessResponse,
Token,
UserDocument,
- Job,
} from "../types";
/**
@@ -216,9 +214,7 @@ class UserController {
async (
req: AuthenticatedRequest,
res: Response
- ): Promise<
- Response
- > => {
+ ): Promise> => {
try {
const method: EditSavedJobsMethod = req.body.method;
const id: string = req.body.id;
@@ -259,9 +255,7 @@ class UserController {
async (
req: AuthenticatedRequest,
res: Response
- ): Promise<
- Response
- > => {
+ ): Promise> => {
try {
const method: EditHiddenJobsMethod = req.body.method;
const id: string = req.body.id;
@@ -303,9 +297,7 @@ class UserController {
req: AuthenticatedRequest,
res: Response
): Promise<
- Response<
- GetSavedJobsDetailsErrorResponse | GetSavedJobsDetailsSuccessResponse
- >
+ Response
> => {
try {
const { savedJobs } = req.user;
@@ -347,10 +339,7 @@ class UserController {
req: AuthenticatedRequest,
res: Response
): Promise<
- Response<
- | GetHiddenJobsDetailsErrorResponse
- | GetHiddenJobsDetailsSuccessResponse
- >
+ Response
> => {
try {
const { hiddenJobs } = req.user;
diff --git a/src/server/types.ts b/src/server/types.ts
index 1c2a006..8f30d67 100644
--- a/src/server/types.ts
+++ b/src/server/types.ts
@@ -15,28 +15,16 @@ export type EditHiddenJobsMethod = "ADD" | "REMOVE";
export type EditSavedJobsMethod = "ADD" | "REMOVE";
-export interface GetJobDetailsErrorResponse {
+export interface ErrorResponse {
error: string;
}
export type GetJobDetailsSuccessResponse = Job;
-export interface GetJobsErrorResponse {
- error: string;
-}
-
export type GetJobsSuccessResponse = GitHubJob[];
-export interface GetHiddenJobsDetailsErrorResponse {
- error: string;
-}
-
export type GetHiddenJobsDetailsSuccessResponse = Job[];
-export interface GetSavedJobsDetailsErrorResponse {
- error: string;
-}
-
export type GetSavedJobsDetailsSuccessResponse = Job[];
export interface GitHubJob {
@@ -87,10 +75,6 @@ export interface JobDocument extends Document {
export type JobType = "Contract" | "Full Time";
-export interface PatchSavedJobErrorResponse {
- error: string;
-}
-
export interface PatchSavedJobSuccessResponse {
createdAt: string;
email: string;
diff --git a/src/server/util.ts b/src/server/util.ts
index d4f7942..069c57a 100644
--- a/src/server/util.ts
+++ b/src/server/util.ts
@@ -1,10 +1,8 @@
import nfetch from "node-fetch";
-import {
- GetJobsErrorResponse,
- GetJobsSuccessResponse,
- GitHubJob,
-} from "./types";
+import JobModel from "./models/Job";
+
+import { ErrorResponse, GetJobsSuccessResponse, GitHubJob, Job } from "./types";
/**
* Check if MongoDB is running locally. Stops application from continuing if false.
@@ -50,7 +48,7 @@ export const createSearchURL = (
};
export const getAllJobsFromAPI = async (): Promise<
- GetJobsErrorResponse | GetJobsSuccessResponse
+ ErrorResponse | GetJobsSuccessResponse
> => {
const jobs: GitHubJob[] = [];
let jobsInBatch = null;
@@ -80,10 +78,42 @@ export const getAllJobsFromAPI = async (): Promise<
};
export const isError = (
- result: GetJobsErrorResponse | GetJobsSuccessResponse
-): result is GetJobsErrorResponse => {
- return (result as GetJobsErrorResponse).error !== undefined;
+ result: ErrorResponse | GetJobsSuccessResponse
+): result is ErrorResponse => {
+ return (result as ErrorResponse).error !== undefined;
};
// eslint-disable-next-line
-export const unique = (arr: any[]): any[] => [...new Set(arr)];
+export const unique = (arr: any[]): any[] =>
+ [...new Set(arr.map((item) => JSON.stringify(item)))].map((item) =>
+ JSON.parse(item)
+ );
+
+export const rehydrateJobsDB = async (): Promise => {
+ try {
+ const result = await getAllJobsFromAPI();
+
+ if (isError(result)) {
+ return result;
+ }
+ // * Drop the current database of Jobs
+ await JobModel.collection.drop();
+
+ // * Create new Job entries
+ await Promise.all(
+ result.map(async (job: GitHubJob) => {
+ const newJobObject: Job = {
+ ...job,
+ listingDate: job.created_at,
+ };
+ const newJob = new JobModel(newJobObject);
+ await newJob.save();
+ return;
+ })
+ );
+
+ return true;
+ } catch (error) {
+ console.error(error);
+ }
+};
diff --git a/template-tsconfig.json b/template-tsconfig.json
deleted file mode 100644
index 1554740..0000000
--- a/template-tsconfig.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "compilerOptions": {
- "jsx": "preserve",
- "target": "ESNext",
- "module": "ESNext",
- "moduleResolution": "node",
- "outDir": "./dist",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "resolveJsonModule": true
- },
- "include": ["./src/**/*", "./index.d.ts"]
-}