diff --git a/cypress/e2e/companiesSpec.cy.js b/cypress/e2e/companiesSpec.cy.js index e6d0fec..c891241 100644 --- a/cypress/e2e/companiesSpec.cy.js +++ b/cypress/e2e/companiesSpec.cy.js @@ -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", { @@ -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", @@ -23,7 +25,7 @@ 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: { @@ -31,6 +33,14 @@ describe("Companies page after logging in", () => { }, }).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("danny_de@email.com"); @@ -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", { @@ -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", @@ -111,7 +123,7 @@ 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: { @@ -119,6 +131,14 @@ describe("Companies page with no companies", () => { } }).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("danny_de@email.com"); diff --git a/cypress/e2e/companyShowSpec.cy.js b/cypress/e2e/companyShowSpec.cy.js index 8de2327..e3becea 100644 --- a/cypress/e2e/companyShowSpec.cy.js +++ b/cypress/e2e/companyShowSpec.cy.js @@ -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", { @@ -9,7 +11,7 @@ describe("Company Show Page", () => { token: "fake-token", user: { data: { - id: 2, + id: userId, type: "user", attributes: { name: "Test User", @@ -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: "johndoe@example.com", + 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: "janesmith@example.com", + 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: { @@ -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("danny_de@email.com"); 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"); }); @@ -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", () => { @@ -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'", () => { diff --git a/cypress/e2e/newCompanySpec.cy.js b/cypress/e2e/newCompanySpec.cy.js index 757b051..72e2c38 100644 --- a/cypress/e2e/newCompanySpec.cy.js +++ b/cypress/e2e/newCompanySpec.cy.js @@ -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 @@ -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", @@ -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: { @@ -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"); @@ -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", () => { diff --git a/src/Interfaces.tsx b/src/Interfaces.tsx index 644bc89..b9fe4d4 100644 --- a/src/Interfaces.tsx +++ b/src/Interfaces.tsx @@ -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; } \ No newline at end of file diff --git a/src/components/JobApplications/JobApplications.tsx b/src/components/JobApplications/JobApplications.tsx index aa9fe41..a3ce4e8 100644 --- a/src/components/JobApplications/JobApplications.tsx +++ b/src/components/JobApplications/JobApplications.tsx @@ -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', diff --git a/src/components/companies/Companies.tsx b/src/components/companies/Companies.tsx index c4d47fd..19b7c81 100644 --- a/src/components/companies/Companies.tsx +++ b/src/components/companies/Companies.tsx @@ -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([]); + const [applications, setApplications] = useState>({}); const [searchTerm, setSearchTerm] = useState(""); const [filteredCompanies, setFilteredCompanies] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -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 = {}; + fetchedApplications.forEach((app: JobApplication) => { + applicationStatusMap[app.company_id] = app.status; + }); setCompanies(companies); + setApplications(applicationStatusMap); setFilteredCompanies(companies); } catch (error) { console.error("Error fetching companies:", error); @@ -86,7 +101,11 @@ function Companies() { onClick={() => navigate(`/companies/${company.id}/contacts`)} > {company.attributes.name} - Not Applied Yet + + {applications[company.id] + ? statusMap[applications[company.id]] + : "Not Applied Yet"} + {company.attributes.notes} ))} diff --git a/src/components/companies/CompanyShow.tsx b/src/components/companies/CompanyShow.tsx index d493883..5e8ccf9 100644 --- a/src/components/companies/CompanyShow.tsx +++ b/src/components/companies/CompanyShow.tsx @@ -3,6 +3,19 @@ import { useParams, Link } from "react-router-dom"; import { getACompany } from "../../trackerApiCalls"; import { useUserLoggedContext } from '../../context/UserLoggedContext'; +interface ContactData { + id: string; + type: string; + attributes: { + first_name: string; + last_name: string; + email: string; + phone_number: string; + notes: string; + user_id: number; + } +} + interface CompanyData { company: { data: { @@ -17,15 +30,11 @@ interface CompanyData { } } }, - contacts: any; // Update this when you want to use the contacts data + contacts: { + data: ContactData[]; + } } -const mockContacts = [ - { id: 1, name: "John Doe", userId: 101 }, - { id: 2, name: "Jane Smith", userId: 102 }, - { id: 3, name: "Alice Johnson", userId: 103 }, -]; - function CompanyShow() { const { id } = useParams<{ id: string }>(); const { token, userData} = useUserLoggedContext(); @@ -69,6 +78,7 @@ function CompanyShow() { } const companyAttributes = companyData.company.data.attributes; + const companyContacts = companyData.contacts.data; return (
@@ -109,17 +119,21 @@ function CompanyShow() { {/* Contacts Section */}

Contacts

-
- {mockContacts.map((contact) => ( - - {contact.name} - - ))} -
+ {companyContacts.length > 0 ? ( +
+ {companyContacts.map((contact) => ( + + {contact.attributes.first_name} {contact.attributes.last_name} + + ))} +
+ ) : ( +

No contacts found for this company

+ )}
diff --git a/src/components/companies/NewCompany.tsx b/src/components/companies/NewCompany.tsx index 57a3da9..10f0711 100644 --- a/src/components/companies/NewCompany.tsx +++ b/src/components/companies/NewCompany.tsx @@ -43,7 +43,6 @@ function NewCompany() { return; } - // Check for duplicate company name const isDuplicate = existingCompanies.some( (company) => company.attributes.name.toLowerCase() === name.trim().toLowerCase() ); @@ -101,6 +100,7 @@ function NewCompany() { type="text" id="companyName" value={name} + placeholder="Company Name" onChange={(e) => setName(e.target.value)} className="p-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" required @@ -114,6 +114,7 @@ function NewCompany() { type="text" id="website" value={website} + placeholder="https://example.com" onChange={(e) => setWebsite(e.target.value)} className="p-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" /> @@ -124,9 +125,9 @@ function NewCompany() { type="text" id="streetAddress" value={streetAddress} + placeholder="123 Main St" onChange={(e) => setStreetAddress(e.target.value)} className="p-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - required />
@@ -135,9 +136,9 @@ function NewCompany() { type="text" id="city" value={city} + placeholder="City" onChange={(e) => setCity(e.target.value)} className="p-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - required />
@@ -146,7 +147,6 @@ function NewCompany() { value={state} onChange={(e) => setState(e.target.value)} className="p-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - required > @@ -207,15 +207,16 @@ function NewCompany() { type="text" id="zipCode" value={zipCode} + placeholder="12345" onChange={(e) => setZipCode(e.target.value)} className="p-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - required />