Table of Contents
-
npm
npm install npm@latest -g
This project uses CircleCI for Continuous Integration (CI). To set up CircleCI for this repository:
-
Sign Up for CircleCI:
- Visit CircleCI and log in using your GitHub account.
-
Authorize CircleCI:
- Allow CircleCI to access this repository.
-
Add the Configuration File:
-
Ensure the
.circleci/config.yml
file is present in the repository. -
The current configuration uses Cypress for testing:
version: 2.1 orbs: cypress: cypress-io/[email protected] workflows: build: jobs: - cypress/run: cypress-command: npx cypress run --headless start-command: npm start
-
-
Verify the CI Pipeline:
- Push your changes to the
main
branch. - Navigate to the CircleCI dashboard to confirm that tests run successfully.
- Push your changes to the
For more information, see the CircleCI Documentation.
- Get a free API Key at https://example.com
- Clone the repo
git clone https://github.com/github_username/repo_name.git
- Install NPM packages
npm install
- Change git remote url to avoid accidental pushes to base project
git remote set-url origin github_username/repo_name git remote -v # confirm the changes
Currently, we will be using Helvetica Neue Sans-Serif as our primary font, with the font size being set using vh/vw.
Example: className="text-[5vw] font-[Helvetica Neue]"
(Note that most text should be Helvetica Neue by default, but if it isn't, setting it manually can be done as above.)
We will be refactoring to make use of MUI's SvgIcon icons, rather than images. Follow the following links for more information about how we'll be doing this: https://mui.com/material-ui/getting-started/ https://mui.com/material-ui/material-icons/?query=home
We'll be using colors according to the image below.
For a form container, we'll be using something like this:
<div className="w-[50vw] mx-auto my-[2vh] p-[3vh] ">
while for our Save Button, we'll be following this example.
bg-cyan-600 text-white px-[2vw] py-[1vh] rounded w-[10vw] hover:bg-cyan-700 focus:ring-cyan-500 focus:ring-2
For our form boxes, we'll be using this styling.
<label htmlFor="email" className="block text-gray-700 font-medium mb-[1vh]"> Email </label> <input className="w-full px-[1vh] py-[1vh] border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-cyan-500" name="email"/>
When we get text that's too long for our designated page area, we will cut that text off after a certain point, then insert a "Read More" button. This will open a modal containing the full version of the previously-truncated text.
When creating tables and forms, we'll be alternating between white and grey-100 for the background, and when we wish to create a button or search bars, we'll generally style them like this unless specifically told otherwise:
<button className='bg-cyan-600 text-white p-[1vh] rounded w-[10vw]'>Add New +</button>
<input className='p-[1vh] border-2 border-slate-800 rounded w-[12vw] h-full' />
<input className='p-[1vh] border-2 border-slate-800 rounded w-[12vw] h-full' />
For an example of what this might look like in practice, see below.
User Context has been implemented!! The use case for the context is getting access to a specific user's information and rather than doing a nightmare of imports and notations to get the info you need; you can call one line of code and get access to the session token for fetches and the loggedIn state for rendering! It keeps the code light, DRY, and easy to develope! Currently there are six pieces of info being given by the context. should there be a need / use case for adding more things to that we can add that at a later date!
-
Import useUserLoggedContext into your component page:
-
$\text{\color{#9d7af5} import}\text{\color{#f5e97a} \{ }\text{\color{#7adef5}useUserLoggedContext}\text{\color{#f5e97a} \}}\text{\color{#9d7af5} from}\text{\color{#fca944} './context/UserLoggedContext.tsx'}$ ;
-
-
Destructure the function call INSIDE your component function:
-
$\text{\color{#2555a8} const}\text{\color{#f5e97a} \{ }\text{\color{#0096db}token, roles, isLoggedIn, userData, userLogged, setUserData, clearUserLogged}\text{\color{#f5e97a} \}}=\text{\color{#fca944} useUserLoggedContext}\text{\color{#9d7af5}()}$ ;
-
-
Use whatever part of the context you need!
At a base level React's createContext function allows a component to share some kind of data with other components that are wrapped in the context.
Calling createContext returns a context object. The context object itself does not hold any information; it represents which part of the context other components can read or use to provide something to other components. Similar to how useState gives you a variable and a setter function that changes that variable; createContext gives you two functions, a
import React, { createContext } from 'react';
export const AUserContextExample = createContext(null)
^ Here we have created our Context with a default value of
import React, { useState, useEffect, useContext } from 'react';
import AUserContextExample from '../contexts/AContextFile.tsx';
import aUserFetchCall from '../apiCalls/ApiCalls.tsx';
import <AnAwesomeComponent /> from '../components/AnAwesomeComponent.tsx';
import <AnEpicComponent /> from '../components/AnEpicComponent.tsx';
import <AnExtreameComponent /> from '../components/AnExtreameComponent.tsx';
async function App () {
const [aUserState, setAUserState] = useState();
useEffect(() => {
const aFetchedUser = await aUserFetchCall();
setAUserState(aFetchedUser);
}, [])
return (
<aUserContextExample.Provider value={aUserState}>
<div>
<h1> Welcome To The Awesome App! </h1>
<AnAwesomeComponent />
<AnEpicComponent />
<AnExtreameComponent />
</div>
</aUserContextExample.Provider>
)
}
^ Here we are properly importing all the necessary pieces of our example application into our App component. As App is completing the mounting phase, we are initiating a fetch call to get a user and
import React, { useContext } from 'react';
import AUserContextExample from '../contexts/AContextFile.tsx';
export Function AnAwesomeComponent () {
const anAwesomeUser = useContext(AUserContextExample);
return (
<div>
<h1>`Hello ${anAwesomeUser.name}! Welcome to the Awesome page!`</h1>
<div>
{
anAwsomeUser.someSickAttributeToMap.map((srslyCoolThing) => {
return (
<div>
<div>{srslyCoolThing.foReal}</div>
<div>{srslyCoolThing.noCap}</div>
<div>{srslyCoolThing.trulyGOATED}</div>
</div>
)
})
}
</div>
</div>
)
}
^ Over in
import React, { createContext, useState, useContext } from 'react';
import { UserData } from '../Interfaces';
interface Value {
token: string | null,
roles: string[] | null,
isLoggedIn: boolean,
userData: UserData,
userLogged: Function,
setUserData: Function,
clearUserLogged: Function
}
const UserLoggedContext = createContext<null | Value>(null);
export function UserLoggedContextProvider({ children }: React.PropsWithChildren) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [token, setToken] = useState<null | string>(null);
const [roles, setRoles] = useState<[] | string[]>([]);
const [userData, setUserData] = useState<UserData>({
token: '',
user: {
data: {
id: 0,
type: 'user',
attributes: {
name: '',
email: '',
companies: []
}
}
}
});
# Function to set the logged-in state
const userLogged = (newToken: string, userRoles: string[]) => {
setIsLoggedIn(true);
setToken(newToken);
setRoles(userRoles);
console.log(userData, '<-- USER DATA SHOULD SET');
};
# Function to clear the logged-in state
const clearUserLogged = () => {
setIsLoggedIn(false)
setToken(null);
setRoles([]);
setUserData({
token: '',
user: {(...)}
});
console.log(userData, '<-- USER DATA SHOULD CLEAR');
};
# Context value
const value = {
token,
roles,
isLoggedIn,
userData,
userLogged,
setUserData,
clearUserLogged,
};
return (
<UserLoggedContext.Provider value={value}>
{children}
</UserLoggedContext.Provider>
)
}
export const useUserLoggedContext = () => {
const context = useContext(UserLoggedContext);
if (!context) {
throw new Error('useUserLogged must be used within a UserLoggedProvider');
}
return context;
}
^ In our Tracker-CRM project; we've executed the
Instead of having App.tsx hold the
We've created a
We then pass that
Wait, if we aren't setting up the
Think of the children!?
In React, children are a special type of prop that allows components to recieve and render other components or elements. The props.children
property gives access to the content between the opening and closing tags of a parent component. As you can see we have destructured the children property as the parameter for the
You'll notice this bit of code underneath the
export const useUserLoggedContext = () => {
const context = useContext(UserLoggedContext);
if (!context) {
throw new Error('useUserLogged must be used within a UserLoggedProvider');
}
return context;
}
^ We've created a
Then we have an if statement checking the
Now I bet you are wondering where we're using the
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { UserLoggedContextProvider } from './context/UserLoggedContext';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode>
<UserLoggedContextProvider>
<App />
</UserLoggedContextProvider>
</React.StrictMode>
</BrowserRouter>
);
^ By wrapping the whole
All this, heady theory stuff aside, structuring our context this way is what allows us to do one import and one line of code to get access to the user data and the session token. Please, if this has not cleared things up or if it could be explained better feel free to edit this README as necessary!
Also if you have read this whole explaination; you're a beast!
Users must register their account to utilize this application.
The User Registration section allows new users to create an account by filling out all necessary fields with the requried information. Empty fields or invalid information throws specific errors instructing users to correct their mistake in order to proceed.
Existing users may click the 'login' link to directly navigate to the Login page.
The MenuBar component provides a responsive navigation interface for your application, designed for both desktop and mobile users. Here’s an overview of its functionality:
- Fixed Vertical Menu: A static vertical navigation bar located on the left side of the screen, hidden on smaller screens.
- Logo: Clicking the logo redirects users to the home page.
- Navigation Links: Includes icons for navigating to key sections:
- Home
- Contacts
- Companies
- Job Applications
- Account
- Drop-Down Shortcut Menu: Provides quick access to add new items:
- Add New Contact
- Add New Company
- Add New Job Application
- Hamburger Menu: A collapsible menu for smaller screens.
- Slide-Out Menu: A sidebar that slides in from the left when opened.
- Close Button: Closes the slide-out menu.
- Navigation Links: Similar to the desktop navigation, but tailored for mobile interaction.
- Drop-Down Shortcut Menu: A simplified version of the desktop drop-down, allowing quick actions for adding new contacts, companies, or job applications.
- Quad Color Bar: A decorative vertical bar split into four colors, enhancing the visual design.
The home page/dash is where a user can see there weekly report.
Functionalities Include:
- User can see the job applications, contacts, and companies they have made for the week.
- as well as having a simple button to port you to add a new company
The Companies section allows users to seamlessly manage a list of their companies.
Key Functionalities Include:
- View All Companies: Browse a comprehensive list of companies with detailed information such as company name, application status, and notes.
- View Company Details: Click on a company to see detailed information on a dedicated page, including the company’s name, website, address, and notes. The details page also displays a list of associated contacts, making it easier to manage relationships and connections.
- Create a Company: Add new companies by filling out a simple form with fields like name, website, address, and notes.
- Search for a Company: Use the search bar to quickly find companies by name, enhancing efficiency and user experience.
The Contacts section allows users to navigate their contacts.
Key Functionalities Include:
- View All Contacts: Browse a comprehensive list of contacts with info like their name, company, and notes. Includes a search bar and ability to create a new contact.
- View a Contact: Click on a contact to see detail info on a dedicated page, such as their name, company, email address, phone number, notes and any other contacts associated with the company.
- Add a new Contact Click on the Add New + button to navigate to a form where a user inputs a new contact and their associated information.
- Search for a Contact Use the search bar to quickly find a contact by name, enhancing efficiency and user experience.
-
View All Job Applications:
-
View A Job Application:
-
Create A Job Application: Add a new job application by filling out a form with fields for Position Title, Company, Date Applied, Application Status, Job Description, Application URL, and Notes. Choose a company that exists under your profile.
- Edit A Job Application: Edit several of the fields of an application that has already been input into the system to stay up to date on where in the process the application is at.
Banks, Charles
Bloom, Stefan
Chirchirillo, Joe
Cirbo, Candice
Croy, Lito
Delaney, Kyle
De La Rosa, Melchor
Galvin, Shane
Hill, John
Hotaling, Marshall
Macur, Jim
Messersmith, Renee
O'Leary, Ryan
Pintozzi, Erin - (Project Manager)
Distributed under the MIT License. See LICENSE.txt
for more information.