Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/companies dynamic #46

Merged
merged 8 commits into from
Jan 7, 2025
Merged
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
28 changes: 24 additions & 4 deletions cypress/e2e/companiesSpec.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { mockCompanies } from "../fixtures/mockCompanies.js";
import { mockEmptyCompanies } from "../fixtures/emptyMockCompanies.js";

describe("Companies page after logging in", () => {
const userId = 2;

beforeEach(() => {
// Intercept the login POST request
cy.intercept("POST", "http://localhost:3001/api/v1/sessions", {
Expand All @@ -10,7 +12,7 @@ describe("Companies page after logging in", () => {
token: "fake-token",
user: {
data: {
id: 2,
id: userId,
type: "user",
attributes: {
name: "Test User",
Expand All @@ -23,14 +25,22 @@ describe("Companies page after logging in", () => {
}).as("mockSession");

// Intercept the GET request to fetch companies
cy.intercept("GET", "http://localhost:3001/api/v1/users/2/companies", {
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/companies`, {
statusCode: 200,
body: mockCompanies,
headers: {
"Content-Type": "application/json",
},
}).as("getCompanies");

// Intercept the GET request to fetch job applications
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/job_applications`,{
statusCode: 200,
body: {
data: [],
},
})

// Visit the login page and perform login
cy.visit("http://localhost:3000/");
cy.get("#email").type("[email protected]");
Expand Down Expand Up @@ -90,6 +100,8 @@ describe("Companies page after logging in", () => {
});

describe("Companies page with no companies", () => {
const userId = 2;

beforeEach(() => {
// Intercept the login POST request
cy.intercept("POST", "http://localhost:3001/api/v1/sessions", {
Expand All @@ -98,7 +110,7 @@ describe("Companies page with no companies", () => {
token: "fake-token",
user: {
data: {
id: 2,
id: userId,
type: "user",
attributes: {
name: "Test User",
Expand All @@ -111,14 +123,22 @@ describe("Companies page with no companies", () => {
}).as("mockSession");

// Intercept the GET request with empty companies
cy.intercept("GET", "http://localhost:3001/api/v1/users/2/companies", {
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/companies`, {
statusCode: 200,
body: mockEmptyCompanies,
headers: {
"Content-Type": "application/json",
}
}).as("getEmptyCompanies");

// Intercept the GET request to fetch job applications
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/job_applications`,{
statusCode: 200,
body: {
data: [],
},
})

// Visit the login page and perform login
cy.visit("http://localhost:3000/");
cy.get("#email").type("[email protected]");
Expand Down
83 changes: 53 additions & 30 deletions cypress/e2e/companyShowSpec.cy.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { mockCompanies } from "../fixtures/mockCompanies.js";

describe("Company Show Page", () => {
const userId = 2;

beforeEach(() => {
// Intercept the login POST request
cy.intercept("POST", "http://localhost:3001/api/v1/sessions", {
Expand All @@ -9,7 +11,7 @@ describe("Company Show Page", () => {
token: "fake-token",
user: {
data: {
id: 2,
id: userId,
type: "user",
attributes: {
name: "Test User",
Expand All @@ -36,10 +38,38 @@ describe("Company Show Page", () => {
},
},
},
contacts: {
data: [
{
id: "101", // Change to string to match interface
type: "contact", // Add type field
attributes: {
first_name: "John",
last_name: "Doe",
email: "[email protected]",
phone_number: "555-1234", // Changed from phone to phone_number
notes: "",
user_id: userId
},
},
{
id: "102",
type: "contact",
attributes: {
first_name: "Jane",
last_name: "Smith",
email: "[email protected]",
phone_number: "555-5678",
notes: "",
user_id: userId
},
},
],
},
};

// Intercept the GET request to fetch companies list
cy.intercept("GET", "http://localhost:3001/api/v1/users/2/companies", {
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/companies`, {
statusCode: 200,
body: mockCompanies,
headers: {
Expand All @@ -48,35 +78,28 @@ describe("Company Show Page", () => {
},
}).as("getCompanies");

// Intercept the GET request to fetch job applications
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/job_applications`,{
statusCode: 200,
body: {
data: [],
},
})

// Intercept the GET request to fetch company details with Authorization header
cy.intercept("GET", "http://localhost:3001/api/v1/users/2/companies/1/contacts", {
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/companies/1/contacts`, {
statusCode: 200,
body: mockCompany,
headers: {
"Content-Type": "application/json",
Authorization: "Bearer fake-token",
},
}).as("getCompany");

// Visit the login page and perform login
cy.visit("http://localhost:3000/");
cy.visit("/");
cy.get("#email").type("[email protected]");
cy.get("#password").type("jerseyMikesRox7");
cy.get('[data-testid="login-button"]').click();
cy.wait("@mockSession");

// Store the token in localStorage
cy.window().then((win) => {
win.localStorage.setItem("token", "fake-token");
});

// Navigate to the Companies page
cy.get('[data-testid="companies-iconD"]').click();
cy.get('a[href="/companies"]').click();
cy.wait("@getCompanies");

cy.log("Navigating to the company details page");

// Click on the first company in the table (assuming it's "Google")
cy.get("table tbody tr").first().click();
cy.wait("@getCompany");
});
Expand Down Expand Up @@ -110,12 +133,17 @@ describe("Company Show Page", () => {
});
});

it("Should display the contacts correctly", () => {
cy.get("h2").contains("Contacts").should("exist");
it("Should display the dynamic contacts correctly", () => {
cy.contains("Contacts").should("exist");

const contacts = [
{ name: "John Doe", link: "/contacts/101" },
{ name: "Jane Smith", link: "/contacts/102" },
];

cy.contains("John Doe").should("have.attr", "href", "/contacts/101");
cy.contains("Jane Smith").should("have.attr", "href", "/contacts/102");
cy.contains("Alice Johnson").should("have.attr", "href", "/contacts/103");
contacts.forEach((contact) => {
cy.contains(contact.name).should("have.attr", "href", contact.link);
});
});

it("Should navigate to the correct contact detail page when a contact is clicked", () => {
Expand All @@ -126,11 +154,6 @@ describe("Company Show Page", () => {

cy.contains("Jane Smith").click();
cy.url().should("include", "/contacts/102");

cy.go("back");

cy.contains("Alice Johnson").click();
cy.url().should("include", "/contacts/103");
});

it("Should navigate back to the companies page when clicking 'Back to Companies'", () => {
Expand Down
37 changes: 30 additions & 7 deletions cypress/e2e/newCompanySpec.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { mockCompanies } from "../fixtures/mockCompanies";

describe("New Company page after logging in", () => {
let uniqueCompanyName = `Test Company ${Date.now()}`;
const userId = 2;

beforeEach(() => {
// Intercept the login POST request
Expand All @@ -11,7 +12,7 @@ describe("New Company page after logging in", () => {
token: "fake-token",
user: {
data: {
id: 2,
id: userId,
type: "user",
attributes: {
name: "Test User",
Expand All @@ -24,13 +25,21 @@ describe("New Company page after logging in", () => {
}).as("mockSession");

// Intercept the GET request to fetch companies
cy.intercept("GET", "http://localhost:3001/api/v1/users/2/companies", {
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/companies`, {
statusCode: 200,
body: mockCompanies,
}).as("getCompanies");

// Intercept the GET request to fetch job applications
cy.intercept("GET", `http://localhost:3001/api/v1/users/${userId}/job_applications`,{
statusCode: 200,
body: {
data: [],
},
});

// Intercept the POST request to create a new company
cy.intercept("POST", "http://localhost:3001/api/v1/users/2/companies", {
cy.intercept("POST", `http://localhost:3001/api/v1/users/${userId}/companies`, {
statusCode: 201,
body: {
data: {
Expand Down Expand Up @@ -79,6 +88,15 @@ describe("New Company page after logging in", () => {
cy.get("label").contains("Notes:").should("exist");
});

it("Should display correct placeholder text in all input fields", () => {
cy.get("#companyName").should("have.attr", "placeholder", "Company Name");
cy.get("#website").should("have.attr", "placeholder", "https://example.com");
cy.get("#streetAddress").should("have.attr", "placeholder", "123 Main St");
cy.get("#city").should("have.attr", "placeholder", "City");
cy.get("#zipCode").should("have.attr", "placeholder", "12345");
cy.get("textarea").should("have.attr", "placeholder", "Notes about the company");
});

it("Should allow input in all form fields", () => {
cy.get("#companyName").type(uniqueCompanyName).should("have.value", uniqueCompanyName);
cy.get("#website").type("www.testcompany.com").should("have.value", "www.testcompany.com");
Expand All @@ -92,10 +110,15 @@ describe("New Company page after logging in", () => {
it("Should require mandatory fields", () => {
cy.get('button[type="submit"]').click();
cy.get("#companyName:invalid").should("exist");
cy.get("#streetAddress:invalid").should("exist");
cy.get("#city:invalid").should("exist");
cy.get("select:invalid").should("exist");
cy.get("#zipCode:invalid").should("exist");
});

it("should allow submission with only the company name filled in", () => {
cy.get("#companyName").type(uniqueCompanyName);
cy.get('button[type="submit"]').click();

cy.wait("@addCompany");
cy.get(".bg-green-100").should("contain.text", "Company added successfully!");
cy.url().should("include", "/companies");
});

it("Should show error for duplicate company name", () => {
Expand Down
13 changes: 13 additions & 0 deletions src/Interfaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,17 @@ export interface Company {
id: number;
type: string;
attributes: CompanyAttributes;
}

export interface JobApplication {
id: string;
position_title: string;
date_applied: string;
status: number;
notes: string;
job_description: string;
application_url: string;
contact_information: string;
company_id: number;
company_name?: string;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of an Interfaces file(and an api fetch file since it's the same idea) for all component usage is mega SRP. Perhaps an issue can be made to migrate all interfaces to this file?

14 changes: 1 addition & 13 deletions src/components/JobApplications/JobApplications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,9 @@ import { Link } from 'react-router-dom';
import { fetchApplicationsData } from '../../apiCalls';
import ClipLoader from "react-spinners/ClipLoader";
import { useUserLoggedContext } from '../../context/UserLoggedContext';
import { JobApplication } from '../../Interfaces';
import useSWR from 'swr';

interface JobApplication {
id: string;
position_title: string;
date_applied: string;
status: number;
notes: string;
job_description: string;
application_url: string;
contact_information: string;
company_id: number;
company_name?: string;
}

const statusMap: { [key: number]: string } = {
1: 'Submitted',
2: 'Interviewing',
Expand Down
25 changes: 22 additions & 3 deletions src/components/companies/Companies.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { useEffect, useState } from "react"
import { Link, useNavigate } from "react-router-dom";
import { Company } from "../../Interfaces";
import { Company, JobApplication } from "../../Interfaces";
import { useUserLoggedContext } from "../../context/UserLoggedContext";
import { fetchCompanies } from "../../trackerApiCalls";
import { fetchApplicationsData } from "../../apiCalls";

const statusMap: { [key: number]: string } = {
1: "Submitted",
2: "Interviewing",
3: "Offer",
4: "Rejected",
5: "Phone Screen",
};

function Companies() {
const [companies, setCompanies] = useState<Company[] | null>([]);
const [applications, setApplications] = useState<Record<number, number>>({});
const [searchTerm, setSearchTerm] = useState("");
const [filteredCompanies, setFilteredCompanies] = useState<Company[]>([]);
const [isLoading, setIsLoading] = useState(true);
Expand All @@ -18,8 +27,14 @@ function Companies() {
const getCompanies = async () => {
try {
const companies = await fetchCompanies(userData.user.data.id, token!);
console.log("fetched companies", companies)
const fetchedApplications = await fetchApplicationsData(userData.user.data.id, token!);

const applicationStatusMap: Record<number, number> = {};
fetchedApplications.forEach((app: JobApplication) => {
applicationStatusMap[app.company_id] = app.status;
});
setCompanies(companies);
setApplications(applicationStatusMap);
setFilteredCompanies(companies);
} catch (error) {
console.error("Error fetching companies:", error);
Expand Down Expand Up @@ -86,7 +101,11 @@ function Companies() {
onClick={() => navigate(`/companies/${company.id}/contacts`)}
>
<td className="p-4 border-b">{company.attributes.name}</td>
<td className="p-4 border-b">Not Applied Yet</td>
<td className="p-4 border-b">
{applications[company.id]
? statusMap[applications[company.id]]
: "Not Applied Yet"}
</td>
<td className="p-4 border-b">{company.attributes.notes}</td>
</tr>
))}
Expand Down
Loading