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 all commits
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 and building the SPA for deployment
- npm for package management and scripting of installed packages

### 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
14 changes: 12 additions & 2 deletions FU.SPA/src/components/Chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import ChatMessage from './ChatMessage';
import UserContext from '../context/userContext';
import config from '../config';

/**
* The Chat component is used to render the chat interface
*
* @param {number} chatId The id of the chat
* @returns The rendered chat component
*/
export default function Chat({ chatId }) {
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
Expand All @@ -27,6 +33,7 @@ export default function Chat({ chatId }) {
const [isNewMessageReceived, setIsNewMessageReceived] = useState(false);
const limit = 25;

// Set the chat messages and join the chat group
useEffect(() => {
const initializeChat = async () => {
try {
Expand All @@ -44,6 +51,7 @@ export default function Chat({ chatId }) {
}
};

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

Expand All @@ -68,6 +76,7 @@ export default function Chat({ chatId }) {
};
}, [chatId, user]);

// Load more messages when user is scrolled near the top
useEffect(() => {
const loadMoreMessages = async () => {
try {
Expand All @@ -91,6 +100,7 @@ export default function Chat({ chatId }) {
}
}, [offset, chatId]);

// Save the message to the database
async function handleSendMessage() {
try {
if (message === '') {
Expand All @@ -103,6 +113,7 @@ export default function Chat({ chatId }) {
}
}

// Handle scrolling to load more messages
const handleScroll = (event) => {
if (event.target.scrollTop === 0) {
if (hasMoreMessages) {
Expand All @@ -111,6 +122,7 @@ export default function Chat({ chatId }) {
}
};

// Scroll to the bottom when messages are updated
useEffect(() => {
// Scroll to the bottom when messages are updated
const chatContainer = document
Expand All @@ -124,8 +136,6 @@ export default function Chat({ chatId }) {
}
}, [messages, prevScrollHeight]);

// Use MUi card for chat

return (
<Card
className="chat-card"
Expand Down
2 changes: 2 additions & 0 deletions FU.SPA/src/components/ChatLocked.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom';
export default function ChatLocked({ chatType, reason, onResolutionClick }) {
const navigate = useNavigate();

// Render the message based on the reason
const renderMessage = () => {
let reasonMessage;

Expand All @@ -29,6 +30,7 @@ export default function ChatLocked({ chatType, reason, onResolutionClick }) {
);
};

// Render the resolution button based on the reason
const renderResolution = () => {
// get the current path
var path = window.location.pathname;
Expand Down
8 changes: 8 additions & 0 deletions FU.SPA/src/components/ChatMessage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import { Avatar } from '@mui/material';
import { useNavigate } from 'react-router-dom';
import DateUtils from '../helpers/dateUtils';

/**
* This component is used to render a chat message
*
* @param {object} chatMessage The chat message object
* @param {boolean} userIsSender A boolean to check if the current user is the sender
*
* @returns The rendered chat message component
*/
export default function ChatMessage({ chatMessage, userIsSender }) {
const user = chatMessage.sender;
const navigate = useNavigate();
Expand Down
7 changes: 7 additions & 0 deletions FU.SPA/src/components/ChatMessagePreview.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { Typography } from '@mui/material';
import DateUtils from '../helpers/dateUtils';

/**
* The ChatMessagePreview component is used to render a chat message preview
*
* @param {object} chatMessage The chat message object
*
* @returns The rendered chat message preview component
*/
export default function ChatMessage({ chatMessage }) {
return (
<div style={{ fontStyle: 'italic' }}>
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 @@ -19,6 +19,7 @@ import UserContext from '../context/userContext';
import dayjs from 'dayjs';
import { Store } from 'react-notifications-component';

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

Expand Down Expand Up @@ -108,6 +109,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 @@ -188,6 +190,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 @@ -353,6 +356,7 @@ const GameSelector = ({ onChange, initialValue }) => {
return filtered;
};

// Returns Game selector field
return (
<Autocomplete
required
Expand Down Expand Up @@ -444,6 +448,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
Loading