Skip to content

Commit

Permalink
organization preps
Browse files Browse the repository at this point in the history
  • Loading branch information
cophilot committed Dec 8, 2023
1 parent 5726a1a commit 036bec5
Show file tree
Hide file tree
Showing 12 changed files with 414 additions and 26 deletions.
5 changes: 5 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ThemeProvider } from './providers/ThemeProvider';
import { UserProvider } from './providers/UserProvider';
import Settings from './components/Settings/Settings';
import { NotificationProvider } from './providers/NotificationProvider';
import CreateOrg from './components/CreateOrg/CreateOrg';

// The main component of the application
function App() {
Expand All @@ -21,6 +22,10 @@ function App() {
<Routes>
<Route path="/" Component={Home} />
<Route path="/login" Component={Login} />
<Route
path="/org/create"
Component={CreateOrg}
/>
<Route
path="/register"
Component={Register}
Expand Down
41 changes: 41 additions & 0 deletions src/components/ChoiceNotification/ChoiceNotification.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.ChoiceNotification {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: var(--btn-color);
width: 400px;
height: 200px;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
border: 2px solid var(--text-color);
color: var(--text-color);
box-shadow: 0 0 10px var(--text-color);
h1 {
margin-top: 40px;
margin-bottom: 10px;
}
button {
background-color: transparent;
color: var(--text-color);
border: 2px solid var(--text-color);
border-radius: 5px;
padding: 5px;
padding-left: 20px;
padding-right: 20px;
font-size: 20px;
cursor: pointer;
&:hover {
background-color: var(--text-color);
color: var(--bg-color);
scale: 1.1;
}
}
.choiceBtns {
display: flex;
justify-content: space-around;
width: 100%;
}
}
3 changes: 3 additions & 0 deletions src/components/ChoiceNotification/ChoiceNotification.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test('ChoiceNotificationTest', () => {
expect(true).toBe(true);
});
40 changes: 40 additions & 0 deletions src/components/ChoiceNotification/ChoiceNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import './ChoiceNotification.scss';

interface Props {
heading: string;
info: string;
onAccept: () => void;
onReject: () => void;
acceptText: string;
rejectText: string;
}

/**
* A notification that is displayed to the user
* @param heading The heading of the notification
* @param info More information about the notification
* @param onClose The function to call when the notification is closed
*/
function ChoiceNotification({
heading,
info,
onAccept,
onReject,
acceptText = 'Yes',
rejectText = 'No',
}: Props) {
return (
<div>
<div className="background" onClick={onReject}></div>
<div className="ChoiceNotification">
<h1>{heading}</h1>
<p>{info}</p>
<div className="choiceBtns">
<button onClick={onReject}>{rejectText}</button>
<button onClick={onAccept}>{acceptText}</button>
</div>
</div>
</div>
);
}
export default ChoiceNotification;
43 changes: 43 additions & 0 deletions src/components/CreateOrg/CreateOrg.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.CreateOrg {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
padding-top: 100px;
h1 {
text-align: center;
}
.errorMsg {
color: red;
font-size: 15px;
font-weight: bold;
text-align: center;
border: none;
box-shadow: none;
min-height: 20px;
}
div {
display: flex;
flex-direction: column;
justify-content: center;
* {
margin: 10px;
}
input {
width: 300px;
height: 30px;
border-radius: 5px;
text-align: center;
font-size: 20px;
background-color: var(--btn-color);
border: 2px solid var(--btn-color);
color: var(--text-color);
&:focus {
outline: none;
border: 2px solid #083d60;
}
}
}
}
3 changes: 3 additions & 0 deletions src/components/CreateOrg/CreateOrg.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test('CreateOrgTest', () => {
expect(true).toBe(true);
});
85 changes: 85 additions & 0 deletions src/components/CreateOrg/CreateOrg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Link, useNavigate } from 'react-router-dom';
import './CreateOrg.scss';
import { useGetUsername, useLoggedIn } from '../../providers/UserProvider';
import { useEffect, useState } from 'react';
import APIService from '../../utils/ApiService';
import { useShowNotification } from '../../providers/NotificationProvider';

/**
* A page to create an organization
*/
function CreateOrg() {
const [errorMessage, setErrorMessage] = useState(' ');
const [name, setName] = useState('');

const navigate = useNavigate();
const showNotification = useShowNotification();

const getUserName = useGetUsername();
const isLoggedIn = useLoggedIn();

const [username] = useState(getUserName());

const onCreateOrg = () => {
if (name === '') {
setErrorMessage('Organization name cannot be empty');
return;
}
if (name.length > 20) {
setErrorMessage(
'Organization name cannot be longer than 20 characters'
);
return;
}
if (name.length < 3) {
setErrorMessage(
'Organization name cannot be shorter than 3 characters'
);
return;
}
APIService.createOrg(username, name).then((suc) => {
if (!suc) {
setErrorMessage('Organization already exists');
return;
}
showNotification(
'Organization created!',
'Organization ' + name + ' created successfully.'
);
navigate('/profile');
});
};

useEffect(() => {
if (!isLoggedIn) {
navigate('/');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoggedIn, username]);

return (
<div className="CreateOrg">
<h1>
wanna<span className="db">db</span> <br />
<i>CREATE ORGANIZATION</i>
</h1>
<div>
<p className="errorMsg">{errorMessage}</p>
<input
type="text"
placeholder="Organization Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>

<button className="btn" onClick={onCreateOrg}>
Create
</button>
<Link className="btn" to="/profile">
Back
</Link>
</div>
</div>
);
}
export default CreateOrg;
6 changes: 6 additions & 0 deletions src/components/Profile/Profile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@
font-weight: bold;
margin-bottom: 20px;
}
.orgBtns {
display: flex;
* {
margin-right: 10px;
}
}
}
64 changes: 62 additions & 2 deletions src/components/Profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigate } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import APIService from '../../utils/ApiService';
import Navbar from '../Navbar/Navbar';
import './Profile.scss';
Expand All @@ -9,30 +9,41 @@ import {
useLoggedIn,
} from '../../providers/UserProvider';
import MyFiles from '../MyFiles/MyFiles';
import { useShowChoiceNotification } from '../../providers/NotificationProvider';

/**
* The profile page component
*/
function Profile() {
const navigate = useNavigate();
const showChoice = useShowChoiceNotification();

const getUserName = useGetUsername();
const isLoggedIn = useLoggedIn();
const logOut = useLogOut();

const [username] = useState(getUserName());
const [fileNames, setFileNames] = useState<string[]>([]);
const getFiles = async () => {
const [organizationName, setOrganizationName] = useState<string>('');

const getFiles = () => {
APIService.getFileNames(username).then((res) => {
setFileNames(res);
});
};

const getOrganizationName = () => {
APIService.getOrganization(username).then((res) => {
setOrganizationName(res);
});
};

useEffect(() => {
if (!isLoggedIn) {
navigate('/');
}
getFiles();
getOrganizationName();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoggedIn, username]);

Expand All @@ -44,6 +55,55 @@ function Profile() {
{username.slice(0, -2)}
<span className="db">{username.slice(-2)}</span>
</h1>
<h2>
<span className="db">My</span>Organization
</h2>
{organizationName !== '' ? (
<p>
<b>{organizationName}</b>
</p>
) : (
<p>
<i>You are not a member of any organization.</i>
</p>
)}

<div className="orgBtns">
{organizationName !== '' ? (
<>
{/* //TODO */}
<button className="btn">View</button>
<button
className="btn"
onClick={() => {
showChoice(
'Leave Organization',
'Are you sure you want to leave ' +
organizationName +
'?',
() => {
// TODO: Leave organization
console.log('Leave');
},
() => {},
'Leave',
'Cancel'
);
}}
>
Leave
</button>
</>
) : (
<>
{/* //TODO */}
<button className="btn">Join</button>
<Link className="btn" to="/org/create">
Create New
</Link>
</>
)}
</div>
<h2>
<span className="db">My</span>Files
</h2>
Expand Down
13 changes: 10 additions & 3 deletions src/components/UserNotification/UserNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ interface Props {
heading: string;
info: string;
onClose: () => void;
btnText?: string;
}

/**
Expand All @@ -12,13 +13,19 @@ interface Props {
* @param info More information about the notification
* @param onClose The function to call when the notification is closed
*/
function UserNotification({ heading, info, onClose }: Props) {
function UserNotification({
heading,
info,
onClose,
btnText = 'Close',
}: Props) {
return (
<div className="background" onClick={onClose}>
<div>
<div className="background" onClick={onClose}></div>
<div className="UserNotification">
<h1>{heading}</h1>
<p>{info}</p>
<button>Close</button>
<button onClick={onClose}>{btnText}</button>
</div>
</div>
);
Expand Down
Loading

0 comments on commit 036bec5

Please sign in to comment.