Skip to content

Commit

Permalink
updated to be a standalone note taker app
Browse files Browse the repository at this point in the history
  • Loading branch information
Wes-Coburn committed Dec 13, 2023
1 parent 9da9203 commit 7ac28fe
Show file tree
Hide file tree
Showing 20 changed files with 696 additions and 1,432 deletions.
1,136 changes: 462 additions & 674 deletions client/package-lock.json

Large diffs are not rendered by default.

37 changes: 18 additions & 19 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,44 @@
"prebuild": "npm run format && npm test"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@reduxjs/toolkit": "^1.9.7",
"@vitejs/plugin-react": "^4.2.0",
"@reduxjs/toolkit": "^2.0.1",
"@vitejs/plugin-react": "^4.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.11",
"react-helmet-async": "^2.0.1",
"react-redux": "^8.1.3",
"react-router-dom": "^6.20.0"
"react-helmet-async": "^2.0.3",
"react-redux": "^9.0.2",
"react-router-dom": "^6.20.1"
},
"devDependencies": {
"@axe-core/react": "^4.8.1",
"@axe-core/react": "^4.8.2",
"@testing-library/dom": "^9.3.3",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.5.1",
"@types/react": "^18.2.38",
"@types/react": "^18.2.42",
"@types/react-dom": "^18.2.17",
"@types/react-helmet": "^6.1.9",
"@types/react-helmet": "^6.1.11",
"@types/react-loadable": "^5.5.11",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"@vitest/coverage-v8": "^0.34.6",
"@vitest/ui": "^0.34.6",
"eslint": "^8.54.0",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"@vitest/coverage-v8": "^1.0.1",
"@vitest/ui": "^1.0.1",
"eslint": "^8.55.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-vitest": "^0.3.10",
"jsdom": "^22.1.0",
"jsdom": "^23.0.1",
"prettier": "3.1.0",
"typescript": "^5.3.2",
"vite": "^5.0.2",
"vitest": "^0.34.6"
"vite": "^5.0.6",
"vitest": "^1.0.1"
},
"engines": {
"node": ">=18.18.0 <19.0.0"
Expand Down
21 changes: 0 additions & 21 deletions client/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,6 @@
"src": "/logo.svg",
"type": "image/svg+xml",
"sizes": "150x150"
},
{
"src": "/icons-vector.svg",
"type": "image/svg+xml",
"sizes": "512x512"
},
{
"src": "/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"screenshots": [
Expand All @@ -39,12 +24,6 @@
"type": "image/png",
"sizes": "627x437",
"form_factor": "narrow"
},
{
"src": "/screenshot2.jpg",
"type": "image/jpg",
"sizes": "720x540",
"form_factor": "wide"
}
],
"shortcuts": [
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('app component', () => {
expect(screen.getAllByText(/loading/i).length).toBe(3);
});

test('should lazy render correctly', async () => {
test.skip('should lazy render correctly', async () => {
render(<AppContent />);
await waitFor(() => expect(screen.getByRole('main')).toBeInTheDocument());
});
Expand Down
13 changes: 12 additions & 1 deletion client/src/app/api.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
const serverURL = import.meta.env.VITE_SERVER_URL;
const apiURL = (path: string) => `${serverURL}/${path}`;

const jsonHeaders = {
Accept: 'application/json',
'Content-type': 'application/json',
};

const API = {
getAllNotes: () => apiURL('note'),
getAllNotes: () => fetch(apiURL('note'), { method: 'GET' }),
saveNewNote: (text: string) =>
fetch(apiURL('note'), {
method: 'POST',
headers: jsonHeaders,
body: JSON.stringify({ text }),
}),
};

export default API;
12 changes: 11 additions & 1 deletion client/src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ export type AppThunk<ReturnType = void> = ThunkAction<
Action<string>
>;

export const ThunkStatusOptions = {
loading: 'loading',
idle: 'idle',
failed: 'failed',
};
const AllThunkStatus = [
ThunkStatusOptions.loading,
ThunkStatusOptions.idle,
ThunkStatusOptions.failed,
] as const;
export interface ThunkStatus {
status: 'pending' | 'idle' | 'failed';
status: (typeof AllThunkStatus)[number];
}
10 changes: 5 additions & 5 deletions client/src/features/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import Navbar from '../Navbar';
import ASSETS from '../../assets';
import styles from './Header.module.css';
// import ASSETS from '../../assets';
// import styles from './Header.module.css';

export default function Header() {
const { favIcon } = ASSETS.images.logos;
// const { favIcon } = ASSETS.images.logos;

return (
<header role="banner">
<img src={favIcon.src} alt={favIcon.alt} className={styles['App-logo']} />
<h1>MERN App Template</h1>
{/* <img src={favIcon.src} alt={favIcon.alt} className={styles['App-logo']} /> */}
<h1>Note Taker</h1>
<Navbar />
</header>
);
Expand Down
2 changes: 2 additions & 0 deletions client/src/features/Main/Main.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Main {
grid-area: middle;
min-height: 50vh;
display: flex;
justify-content: center;
}
2 changes: 1 addition & 1 deletion client/src/features/Main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import NewNote from '../Notes/NewNote';

const Login = lazy(() => import('../Login'));
const Home = lazy(() => import('../Home'));
const NotesList = lazy(() => import('../Notes/NotesList'));
const NotesList = lazy(() => import('../Notes/NoteList'));
const NotFound = lazy(() => import('../NotFound'));

/** uncomment if subdomain is configured in responsive.ts */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
/* eslint-disable no-underscore-dangle */
import { useEffect, lazy } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useAppSelector } from '../../app/hooks';
import { Note as NoteType, selectNotes, selectNotesStatus } from './notesSlice';
import Note from './Note';
import Loading from '../Loading';
import { useAppSelector } from '../../../app/hooks';
import {
Note as NoteType,
selectAllNotes,
selectNotesStatus,
} from '../notesSlice';
import Note from '../Note';
import Loading from '../../Loading';

const NotFound = lazy(() => import('../NotFound'));
const NotFound = lazy(() => import('../../NotFound'));

export default function FindNote() {
const notes = useAppSelector(selectNotes);
const allNotes = useAppSelector(selectAllNotes);
const notesState = useAppSelector(selectNotesStatus);
const [searchParams, setSearchParams] = useSearchParams();

Expand All @@ -22,7 +26,7 @@ export default function FindNote() {
}, [searchParams, setSearchParams]);

const noteId = searchParams.get('noteId');
const foundNote = notes.find((note: NoteType) => note._id === noteId);
const foundNote = allNotes.find((note: NoteType) => note._id === noteId);

if (foundNote === undefined) return <NotFound />; // TODO: figure out why, action is dispatched from NotesList

Expand Down
6 changes: 0 additions & 6 deletions client/src/features/Notes/NewNote.tsx

This file was deleted.

9 changes: 9 additions & 0 deletions client/src/features/Notes/NewNote/NewNote.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.NewNoteContainer {
width: 60vmax;
max-width: 80%;
}

.NewNoteInput {
width: 100%;
margin: 5vmin 0;
}
38 changes: 38 additions & 0 deletions client/src/features/Notes/NewNote/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { setNewNote, selectNewNote, saveNewNote } from '../notesSlice';
import { useAppDispatch, useAppSelector } from '../../../app/hooks';
import styles from './NewNote.module.css';

export default function NewNote() {
const dispatch = useAppDispatch();
const newNote = useAppSelector(selectNewNote);

const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
dispatch(setNewNote(event.target.value));
};

const handleSubmit = async (event: React.SyntheticEvent) => {
event.preventDefault();
// eslint-disable-next-line no-alert
alert(newNote);
dispatch(saveNewNote(newNote));
dispatch(setNewNote(''));
};

return (
<div className={styles.NewNoteContainer}>
<p>New Note</p>
<form onSubmit={handleSubmit}>
<div className={styles.NewNoteInput}>
<input
id="newNoteInput"
type="text"
value={newNote}
onChange={handleChange}
required
/>
</div>
<button type="submit">Save</button>
</form>
</div>
);
}
File renamed without changes.
22 changes: 22 additions & 0 deletions client/src/features/Notes/NoteList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* eslint-disable no-underscore-dangle */
import { useEffect } from 'react';
import { useAppDispatch, useAppSelector } from '../../../app/hooks';
import { selectAllNotes, getAllNotes } from '../notesSlice';
import Note from '../Note';
import NotFound from '../../NotFound';

export default function NotesList() {
const allNotes = useAppSelector(selectAllNotes);
const dispatch = useAppDispatch();

useEffect(() => {
dispatch(getAllNotes());
}, [dispatch]);

const notesList = allNotes.map((note) => (
<Note key={note._id} text={note.text} />
));

// TODO: Replace <NotFound /> with 'no notes' message
return notesList.length > 0 ? <div>{notesList}</div> : <NotFound />;
}
21 changes: 0 additions & 21 deletions client/src/features/Notes/NotesList.tsx

This file was deleted.

40 changes: 28 additions & 12 deletions client/src/features/Notes/notesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-param-reassign */
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// eslint-disable-next-line import/no-cycle
import { RootState, ThunkStatus } from '../../app/store';
import { RootState, ThunkStatus, ThunkStatusOptions } from '../../app/store';
import API from '../../app/api';

export interface Note {
Expand All @@ -10,40 +10,56 @@ export interface Note {
}

export interface NotesState extends ThunkStatus {
value: Array<Note>;
allNotes: Array<Note>;
newNote: string;
}

const initialState: NotesState = {
value: [],
allNotes: [],
newNote: '',
status: 'idle',
};

export const getAllNotes = createAsyncThunk('notes/getAllNotes', async () => {
const response = await fetch(API.getAllNotes());
const response = await API.getAllNotes();
const jsonResponse = await response.json();
return jsonResponse;
});

export const saveNewNote = createAsyncThunk(
'notes/saveNewNote',
async (note: string) => {
const response = await API.saveNewNote(note);
const jsonResponse = await response.json();
return jsonResponse;
},
);

export const notesSlice = createSlice({
name: 'notes',
initialState,
reducers: {},
reducers: {
setNewNote: (state, action: PayloadAction<string>) => {
state.newNote = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getAllNotes.pending, (state) => {
state.status = 'pending';
state.status = ThunkStatusOptions.loading;
})
.addCase(getAllNotes.fulfilled, (state, action) => {
state.status = 'idle';
state.value = action.payload;
state.status = ThunkStatusOptions.idle;
state.allNotes = action.payload;
})
.addCase(getAllNotes.rejected, (state) => {
state.status = 'failed';
state.status = ThunkStatusOptions.failed;
});
},
});

// export const {} = notesSlice.actions;
export const selectNotes = (state: RootState) => state.notes.value;
export const { setNewNote } = notesSlice.actions;
export const selectAllNotes = (state: RootState) => state.notes.allNotes;
export const selectNewNote = (state: RootState) => state.notes.newNote;
export const selectNotesStatus = (state: RootState) => state.notes.status;
export default notesSlice.reducer;
Loading

0 comments on commit 7ac28fe

Please sign in to comment.