-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Includes significant refactoring and enhancements across various comp…
…onents. It fixes issues with form validation, error handling, and authentication flows. The logout functionality is improved to ensure a smooth user experience. Additionally, custom hooks for authentication and persistence are added. Global styles are updated for a consistent UI. The server-side code is also refined for better error handling and functionality.
- Loading branch information
1 parent
cec7f3c
commit 720fb14
Showing
24 changed files
with
692 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,21 @@ | ||
# User Stories for the app | ||
|
||
1. [ ] Replace current sticky note system | ||
1. [x] Replace current sticky note system | ||
2. [x] Add a public facing page with basic contact info | ||
3. [ ] Add an employee login to the notes app | ||
3. [x] Add an employee login to the notes app | ||
4. [x] Provide a welcome page after login | ||
5. [ ] Provide easy navigation | ||
6. [ ] Display current user and assigned role | ||
7. [ ] Provide a logout option | ||
8. [ ] Require users to login at least once per week | ||
9. [ ] Provide a way to remove employee access asap if needed | ||
5. [x] Provide easy navigation | ||
6. [x] Display current user and assigned role | ||
7. [x] Provide a logout option | ||
8. [x] Require users to login at least once per week | ||
9. [x] Provide a way to remove employee access asap if needed | ||
10. [x] Notes are assigned to specific employees | ||
11. [ ] Notes have a ticket #, title, note body, created & updated dates | ||
11. [x] Notes have a ticket #, title, note body, created & updated dates | ||
12. [x] Notes are either OPEN or COMPLETED | ||
13. [ ] Users can be Employees, Managers, or Admins | ||
14. [ ] Notes can only be deleted by Managers or Admins | ||
15. [ ] Anyone can create a note (when customer checks-in) | ||
16. [ ] Employees can only view and edit their assigned notes | ||
17. [ ] Managers and Admins can view, edit, and delete all notes | ||
18. [ ] Only Managers and Admins can access User Settings | ||
19. [ ] Only Managers and Admins can create new users | ||
13. [x] Users can be Employees, Managers, or Admins | ||
14. [x] Notes can only be deleted by Managers or Admins | ||
15. [x] Anyone can create a note (when customer checks-in) | ||
16. [x] Employees can only view and edit their assigned notes | ||
17. [x] Managers and Admins can view, edit, and delete all notes | ||
18. [x] Only Managers and Admins can access User Settings | ||
19. [x] Only Managers and Admins can create new users |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,55 @@ | ||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; | ||
import { setCredentials } from '../../features/auth/authSlice'; | ||
|
||
const baseQuery = fetchBaseQuery({ | ||
baseUrl: 'http://localhost:3500', | ||
credentials: 'include', | ||
prepareHeaders: (headers, { getState }) => { | ||
const token = getState().auth.token | ||
|
||
if (token) { | ||
headers.set("authorization", `Bearer ${token}`) | ||
} | ||
return headers | ||
} | ||
}) | ||
|
||
const baseQueryWithReauth = async (args, api, extraOptions) => { | ||
// console.log(args) // request url, method, body | ||
// console.log(api) // signal, dispatch, getState() | ||
// console.log(extraOptions) //custom like {shout: true} | ||
|
||
let result = await baseQuery(args, api, extraOptions); | ||
|
||
// If you want, handle other status codes, too | ||
if (result?.error?.status === 403) { | ||
console.log('sending refresh token') | ||
|
||
// send refresh token to get new access token | ||
const refreshResult = await baseQuery('/auth/refresh', api, extraOptions); | ||
|
||
if (refreshResult?.data) { | ||
|
||
// store the new token | ||
api.dispatch(setCredentials({ ...refreshResult.data })) | ||
|
||
// retry original query with new access token | ||
result = await baseQuery(args, api, extraOptions) | ||
} else { | ||
|
||
if (refreshResult?.error?.status === 403) { | ||
refreshResult.error.data.message = "Your login has expired. " | ||
} | ||
return refreshResult | ||
} | ||
}; | ||
|
||
return result; | ||
}; | ||
|
||
// Create an API slice using createApi | ||
export const apiSlice = createApi({ | ||
// Specify the baseQuery configuration with the base URL | ||
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:3500' }), | ||
// Define tagTypes for caching and invalidation | ||
baseQuery: baseQueryWithReauth, | ||
tagTypes: ['Note', 'User'], | ||
// Define endpoints using the builder function | ||
endpoints: builder => ({}) | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,147 @@ | ||
import { Link } from "react-router-dom"; | ||
import { useEffect } from 'react' | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' | ||
import { | ||
faFileCirclePlus, | ||
faFilePen, | ||
faUserGear, | ||
faUserPlus, | ||
faRightFromBracket | ||
} from "@fortawesome/free-solid-svg-icons" | ||
import { useNavigate, Link, useLocation } from 'react-router-dom' | ||
|
||
import { useSendLogoutMutation } from '../features/auth/authApiSlice' | ||
|
||
import useAuth from '../hooks/useAuth' | ||
|
||
const DASH_REGEX = /^\/dash(\/)?$/ | ||
const NOTES_REGEX = /^\/dash\/notes(\/)?$/ | ||
const USERS_REGEX = /^\/dash\/users(\/)?$/ | ||
|
||
const DashHeader = () => { | ||
const { isManager, isAdmin } = useAuth() | ||
|
||
const navigate = useNavigate() | ||
const { pathname } = useLocation() | ||
|
||
const [sendLogout, { | ||
isLoading, | ||
isSuccess, | ||
isError, | ||
error | ||
}] = useSendLogoutMutation() | ||
|
||
useEffect(() => { | ||
if (isSuccess) navigate('/') | ||
}, [isSuccess, navigate]) | ||
|
||
const onNewNoteClicked = () => navigate('/dash/notes/new') | ||
const onNewUserClicked = () => navigate('/dash/users/new') | ||
const onNotesClicked = () => navigate('/dash/notes') | ||
const onUsersClicked = () => navigate('/dash/users') | ||
|
||
let dashClass = null | ||
if (!DASH_REGEX.test(pathname) && !NOTES_REGEX.test(pathname) && !USERS_REGEX.test(pathname)) { | ||
dashClass = "dash-header__container--small" | ||
} | ||
|
||
let newNoteButton = null | ||
if (NOTES_REGEX.test(pathname)) { | ||
newNoteButton = ( | ||
<button | ||
className="icon-button" | ||
title="New Note" | ||
onClick={onNewNoteClicked} | ||
> | ||
<FontAwesomeIcon icon={faFileCirclePlus} /> | ||
</button> | ||
) | ||
} | ||
|
||
let newUserButton = null | ||
if (USERS_REGEX.test(pathname)) { | ||
newUserButton = ( | ||
<button | ||
className="icon-button" | ||
title="New User" | ||
onClick={onNewUserClicked} | ||
> | ||
<FontAwesomeIcon icon={faUserPlus} /> | ||
</button> | ||
) | ||
} | ||
|
||
let userButton = null | ||
if (isManager || isAdmin) { | ||
if (!USERS_REGEX.test(pathname) && pathname.includes('/dash')) { | ||
userButton = ( | ||
<button | ||
className="icon-button" | ||
title="Users" | ||
onClick={onUsersClicked} | ||
> | ||
<FontAwesomeIcon icon={faUserGear} /> | ||
</button> | ||
) | ||
} | ||
} | ||
|
||
let notesButton = null | ||
if (!NOTES_REGEX.test(pathname) && pathname.includes('/dash')) { | ||
notesButton = ( | ||
<button | ||
className="icon-button" | ||
title="Notes" | ||
onClick={onNotesClicked} | ||
> | ||
<FontAwesomeIcon icon={faFilePen} /> | ||
</button> | ||
) | ||
} | ||
|
||
const logoutButton = ( | ||
<button | ||
className="icon-button" | ||
title="Logout" | ||
onClick={sendLogout} | ||
> | ||
<FontAwesomeIcon icon={faRightFromBracket} /> | ||
</button> | ||
) | ||
|
||
const errClass = isError ? "errmsg" : "offscreen" | ||
|
||
let buttonContent | ||
if (isLoading) { | ||
buttonContent = <p>Logging Out...</p> | ||
} else { | ||
buttonContent = ( | ||
<> | ||
{newNoteButton} | ||
{newUserButton} | ||
{notesButton} | ||
{userButton} | ||
{logoutButton} | ||
</> | ||
) | ||
} | ||
|
||
const content = ( | ||
<header className="dash-header"> | ||
<div className="dash-header__container"> | ||
<Link to="/dash"> | ||
<h1 className="dash-header__title">fixScribe</h1> | ||
</Link> | ||
<nav className="dash-header__nav"> | ||
{/* add nav buttons later */} | ||
</nav> | ||
</div> | ||
</header> | ||
<> | ||
<p className={errClass}>{error?.data?.message}</p> | ||
|
||
<header className="dash-header"> | ||
<div className={`dash-header__container ${dashClass}`}> | ||
<Link to="/dash"> | ||
<h1 className="dash-header__title">techNotes</h1> | ||
</Link> | ||
<nav className="dash-header__nav"> | ||
{buttonContent} | ||
</nav> | ||
</div> | ||
</header> | ||
</> | ||
) | ||
|
||
return content | ||
} | ||
|
||
export default DashHeader |
Oops, something went wrong.