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

Added comments and update README.md #543

Merged
merged 5 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
39 changes: 37 additions & 2 deletions FU.SPA/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,45 @@
# SPA Overview

## Tech Stack

- SPA is built with React
- - Material UI is used for common components, some components are custom or modified versions of MUI components
- - Vite is used for local development hosting of the SPA
- NPM for package management

### Understanding Components

Components are rendered and displayed on the page. They integrate JavaScript code and React's JSX syntax to allow for complex functionality to be added to webpages.
Components are displayed in the Document Object Model, or DOM. Each component is a child of the root of the DOM, and components can be children of other comopnents.
This allows passing properties and information down to components, such as passing a title/username from a parent component down to a child.

### Understanding Contexts

Contexts are a way to pass data through the component tree/DOM without having to do it at every level. This simplifies a lot of logic for several different scenarios.
Things like a username, authentication token, login status, and more are not easily passed down through the DOM. For example, our `UserContext` looks like this:

```
const UserContext = createContext({
user: null,
token: null,
login: () => {},
logout: () => {},
refreshUser: () => {},
});
```

This allows us to keep track of the user and call its properties at any level, as well as the user's authentication token.

### Understanding Services

Services are just thin wrappers used by the SPA to ease calling the API and allow for reuse of common API calls.
See the (API services)[https://github.com/SCCapstone/PalmettoProgrammers/blob/main/FU.API/README.md#understanding-services] for understanding of how they work.

## Development

Install [npm](https://www.npmjs.com/package/npm) and [Docker](https://www.docker.com/get-started/).

## Configure the API URL
### Configure the API URL

Config settings are loaded from environment variables. To automatically load environment variables from a file, create a `.env` file in this folder.

Expand All @@ -14,7 +49,7 @@ Set the `VITE_API_URL` environment variable by adding the following to `.env`.

If there are CORS errors, change the URL to match `http://` instead of `https://` and this may resolve the issue.

## Running with docker
### Running with Docker

Add the following to your `hosts` file (`/etc/hosts` on Linux and `C:\Windows\System32\drivers\etc` on Windows).

Expand Down
4 changes: 4 additions & 0 deletions FU.SPA/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import EditPost from './components/pages/EditPost';
import { ReactNotifications } from 'react-notifications-component';
import 'react-notifications-component/dist/theme.css';

/* Top level of application
* Provides theme, notifications, general CSS, User Context, Navbar,
* and top level routes
*/
function App() {
return (
<ThemeProvider theme={Theme}>
Expand Down
2 changes: 2 additions & 0 deletions FU.SPA/src/Theme.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { createTheme } from '@mui/material/styles';

// Main color palatte for the application
const COLORS = {
PRIMARY_MAIN: '#e354dc',
SECONDARY_MAIN: '#4290f5',
BACKGROUND_PAPER: '#31084a',
BACKGROUND_DEFAULT: '#23194f',
};

// Create Theme for the ThemeProvider
const Theme = createTheme({
palette: {
mode: 'dark',
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/Chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default function Chat({ chatId }) {
}
};

// Handles receiving messages
const handleReceiveMessage = (receivedMessage) => {
setMessages((prevMessages) => [...prevMessages, receivedMessage]);

Expand Down
10 changes: 1 addition & 9 deletions FU.SPA/src/components/CreateGroup.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// NOTE: unused component and deprecated
import {
Button,
TextField,
Expand All @@ -11,15 +12,6 @@ import { TextareaAutosize } from '@mui/base/TextareaAutosize';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import Radio from '@mui/material/Radio';

// TODO remove, this demo shouldn't need to reset the theme.

//const defaultTheme = createTheme();

//Look at changing to const CreatePost = () => {
// CreatingPost();
//} or something similiar.
//Design of the page.// TODO START OF PAGE CODE, WHICH I'M CHANGING TO CREATE GROUP, BEFORE MAKING IT A BUTTON FUNCTION (semi-completed)
// need to add a group image and an upload button to the left under the buttons that will be placed there, as well.
export default function CreateGroup() {
return (
<ThemeProvider theme={createTheme}>
Expand Down
2 changes: 2 additions & 0 deletions FU.SPA/src/components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default function Navbar() {
},
}));

// Renders the profile picture and username on the navbar
const renderProfile = () => (
<>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
Expand Down Expand Up @@ -182,6 +183,7 @@ export default function Navbar() {
setAnchorElUser(null);
};

// Displays navbar component
return (
<AppBar position="sticky" enableColorOnDark>
<Toolbar>
Expand Down
5 changes: 5 additions & 0 deletions FU.SPA/src/components/PostCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import dayjs from 'dayjs';
import { Done } from '@mui/icons-material';
import ChatMessagePreview from './ChatMessagePreview';

// Function that displays a card with details of a given post
const PostCard = ({ post, showActions, onTagClick, showJoinedStatus }) => {
const navigate = useNavigate();
const user = post.creator;
Expand All @@ -24,6 +25,7 @@ const PostCard = ({ post, showActions, onTagClick, showJoinedStatus }) => {
showActions = true;
}

//
const handleTagClick = (tag) => {
if (onTagClick) {
onTagClick(tag);
Expand All @@ -49,6 +51,7 @@ const PostCard = ({ post, showActions, onTagClick, showJoinedStatus }) => {
let postEndDateTime = dayjs(post.endTime);

let startDate = dayjs(post.startTime).format('MMM D, YYYY');
// This block handles formatting of start date display on card
if (postStartDateTime < startOfToday) {
// Use default
} else if (postStartDateTime < startOfToday.add(1, 'day')) {
Expand All @@ -64,6 +67,7 @@ const PostCard = ({ post, showActions, onTagClick, showJoinedStatus }) => {
let endDate = '';
if (!postEndDateTime.isSame(postStartDateTime, 'day')) {
endDate = dayjs(post.endTime).format('MMM D, YYYY');
// This block handles formatting of end date display on card
if (postEndDateTime < startOfToday) {
// Use default
} else if (postEndDateTime < startOfToday.add(1, 'day')) {
Expand Down Expand Up @@ -109,6 +113,7 @@ const PostCard = ({ post, showActions, onTagClick, showJoinedStatus }) => {
return color;
};

// Returns card with post details to be displayed
return (
<Card sx={{ width: 250 }}>
<CardContent sx={{ textAlign: 'left', height: 350 }}>
Expand Down
5 changes: 5 additions & 0 deletions FU.SPA/src/components/PostForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import GameService from '../services/gameService';
import UserContext from '../context/userContext';
import dayjs from 'dayjs';

// Function that displays a post form when creating or editing posts
const PostForm = ({ onSubmit, submitButtonText, initialValue }) => {
const { user } = useContext(UserContext);

Expand Down Expand Up @@ -107,6 +108,7 @@ const PostForm = ({ onSubmit, submitButtonText, initialValue }) => {
}
};

// Handles description change state error
const handleDescriptionChange = (e) => {
if (e.length > 1500) {
setDescriptionError('Description cannot exceed 1500 characters');
Expand Down Expand Up @@ -169,6 +171,7 @@ const PostForm = ({ onSubmit, submitButtonText, initialValue }) => {
return tags?.map((tag) => tag.name);
};

// Returns form component to be displayed
return (
<Box sx={{ display: 'flex', justifyContent: 'center', gap: '30px' }}>
<div>
Expand Down Expand Up @@ -334,6 +337,7 @@ const GameSelector = ({ onChange, initialValue }) => {
return filtered;
};

// Returns Game selector field
return (
<Autocomplete
required
Expand Down Expand Up @@ -425,6 +429,7 @@ const TagsSelector = ({ onChange, initialValues }) => {
return filtered;
};

// Returns tag selector field
return (
<Autocomplete
autoHighlight
Expand Down
3 changes: 3 additions & 0 deletions FU.SPA/src/components/PostUsersList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import PostService from '../services/postService';
import './PostUsersList.css';
import { useNavigate } from 'react-router-dom';

// Component that displays all users that have joined a post
export default function PostUsersList({ postId }) {
const [users, setUsers] = useState([]);

Expand Down Expand Up @@ -91,6 +92,7 @@ const UserListItem = ({ user }) => {
return initials;
};

// Display profile picture and names of users in a post
const renderPfp = () => {
return defaultPfp ? (
<Avatar
Expand All @@ -111,6 +113,7 @@ const UserListItem = ({ user }) => {
);
};

// Display status of users in a post
const renderOnlineStatus = (isOnline) => {
if (!isOnline) return;

Expand Down
4 changes: 3 additions & 1 deletion FU.SPA/src/components/ProtectedRoute.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Navigate } from 'react-router-dom';
import UserContext from '../context/userContext';
import config from '../config';

// Function that handles protecting routes based on user authorization level
export const ProtectedRoute = ({ children }) => {
const { user } = useContext(UserContext);
const [isLoading, setIsLoading] = useState(true);
Expand All @@ -12,7 +13,8 @@ export const ProtectedRoute = ({ children }) => {

useEffect(() => {
const delay = async () => {
// See #281: We need to wait for the user to be set before rendering the children
// See #281: We need to wait for the user to be set before rendering the
// children
await new Promise((resolve) => setTimeout(resolve, config.WAIT_TIME));
setIsLoading(false);
};
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/TextSearch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TextField, InputAdornment, IconButton } from '@mui/material';
import { useEffect, useState } from 'react';
import SearchIcon from '@mui/icons-material/Search';

// Component search bar that handles searching of posts and users
function SearchBar({ searchText, onSearchSubmit }) {
const [localSearchText, setLocalSearchText] = useState(searchText);

Expand Down
3 changes: 3 additions & 0 deletions FU.SPA/src/components/UserCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useNavigate } from 'react-router-dom';
import { People, PendingActions, CallMade } from '@mui/icons-material';
import ChatMessagePreview from './ChatMessagePreview';

// Function that displays a card with details of a given user
const UserCard = ({ user, showRelationStatus, showActions }) => {
if (showRelationStatus === undefined) {
showRelationStatus = false;
Expand Down Expand Up @@ -42,6 +43,7 @@ const UserCard = ({ user, showRelationStatus, showActions }) => {
(today.getTime() - dob.getTime()) / (1000 * 3600 * 24 * 365),
);

// Handles displaying relationship status with another user
const renderRelationStatus = () => {
if (!showRelationStatus) {
return null;
Expand Down Expand Up @@ -70,6 +72,7 @@ const UserCard = ({ user, showRelationStatus, showActions }) => {
}
};

// Return card to be displayed
return (
<Card
style={{
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/pages/AccountSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export default function AccountSettings() {
}
};

// Returns a Dialog that displays the delete action confirmation
return (
<Dialog open={deleteDialogOpen} onClose={handleClose}>
<DialogTitle>Are you sure you want to delete your account?</DialogTitle>
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/pages/CreatePost.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
import { Store } from 'react-notifications-component';
import PostForm from '../PostForm';

// Create post page
export default function CreatePost() {
const navigate = useNavigate();

Expand Down
14 changes: 13 additions & 1 deletion FU.SPA/src/components/pages/Discover.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const paramKey = {
userSort: 'usort',
};

// Converts a search paramater to its dayjs equivalent
const paramToDayjs = (searchParams, paramKey) => {
let paramValue = searchParams.get(paramKey);
if (!paramValue || !dayjs(paramValue).isValid()) return undefined;
Expand All @@ -45,6 +46,7 @@ export default function Discover() {
Users: 'Users',
};

// STATE VARIABLES START
const queryLimit = 12;
const [totalResults, setTotalResults] = useState(0);
const [searchParams, setSearchParams] = useSearchParams();
Expand Down Expand Up @@ -112,11 +114,17 @@ export default function Discover() {
const [endTime, setEndTime] = useState(
paramToDayjs(searchParams, paramKey.endTime),
);
// STATE VARIABLES END

// useEffect to update search params
useEffect(() => {
const updateSearchParams = async () => {
setSearchParams(
(params) => {
/* This large block sets the search paramters for a query
* Also handles error checking so that invalid params cannot
* be included
*/
if (
dateRangeRadioValue === DateFilterRadioValues.between &&
startDate?.isValid()
Expand Down Expand Up @@ -189,7 +197,6 @@ export default function Discover() {
);
};

//TODO pull this out to directly call
const updateSearchResults = async () => {
if (tabOption === tabOptions.Posts) {
const query = {
Expand Down Expand Up @@ -318,6 +325,7 @@ export default function Discover() {
}
};

// Render posts or users based on tab option selected
const renderTabContent = () => {
if (tabOption === tabOptions.Posts) {
return (
Expand All @@ -328,6 +336,7 @@ export default function Discover() {
}
};

// Displays post sort selector for sort options
const renderPostSortSelector = () => {
return (
<SortOptionsSelector
Expand All @@ -341,6 +350,7 @@ export default function Discover() {
);
};

// Displays user sort selector for sort options
const renderUserSortSelector = () => {
return (
<SortOptionsSelector
Expand All @@ -354,6 +364,7 @@ export default function Discover() {
);
};

// Displays tab options, currently for posts or users
const renderTabSelectors = () => {
return (
<Tabs
Expand All @@ -370,6 +381,7 @@ export default function Discover() {
);
};

// Display page
return (
<div className="page-content">
<div
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/pages/EditPost.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Store } from 'react-notifications-component';

// Edit post page
export default function EditPost() {
const { postId } = useParams();
const [ogPost, setOgPost] = useState();
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/pages/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import DiscoverPostScreenshot from '../../../assets/discover-posts-view.png';
import PostViewScreenshot from '../../../assets/post-view.png';
import FriendsViewScreenshot from '../../../assets/friends-view.png';

// Home landing page
const Home = () => {
return (
<Box sx={{ maxWidth: 800, p: 2, mx: 'auto', textAlign: 'left' }}>
Expand Down
1 change: 1 addition & 0 deletions FU.SPA/src/components/pages/NoPage.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// 404 error page
export default function NoPage() {
return <h1>404</h1>;
}
Loading
Loading