Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
96f810d
create selectable participantList skeleton
RosaGao Mar 27, 2022
8d4ce18
modify typeof Participant
RosaGao Mar 27, 2022
d86655e
create TimeSlot interface
RosaGao Mar 27, 2022
a170249
fix naming inconsistency
RosaGao Mar 27, 2022
da82365
select multiple members, record ids to show choice
RosaGao Mar 27, 2022
f597b13
Store members in Meeting & make naming consistent
K02D Mar 27, 2022
b609be5
copy url to clipboard on clicking share button
RosaGao Mar 27, 2022
edfb3e8
adding style to memberList
RosaGao Mar 27, 2022
dc047dc
Add unique URL routes for each meeting
K02D Mar 28, 2022
0d6e6aa
Merge branch 'feature/participantList' of https://github.com/Semester…
K02D Mar 28, 2022
e1bf234
style landingPage w/ flexbox, add css file
RosaGao Mar 28, 2022
ba09100
Merge branch 'feature/participantList' of https://github.com/Semester…
RosaGao Mar 28, 2022
f04d8e1
fix merge conflicts
RosaGao Mar 28, 2022
14ac2cd
styling schedule page w/ grid, add css
RosaGao Mar 28, 2022
590e687
Add reducers to update state once meeting is fetched
K02D Mar 29, 2022
14e35c5
Rename Schedule to Meeting
K02D Mar 29, 2022
c258542
Add reducers to update id and members
K02D Mar 29, 2022
dcaa356
Correct MemberType interface
K02D Mar 29, 2022
d0e4ae9
Add and store new member
K02D Mar 29, 2022
c2db397
Make MemberList dynamic
K02D Mar 29, 2022
30baade
sync changes
RosaGao Apr 2, 2022
55ac9fd
add & organize API related function for global use
RosaGao Apr 2, 2022
30db630
save memberId to store, among others (may delete)
RosaGao Apr 2, 2022
7b35449
calculate, format, & PUT timeslots to backend
RosaGao Apr 3, 2022
02888c4
may use ref and HOC to display diff cell colors
RosaGao Apr 3, 2022
a2503c9
Merge branch 'main' of https://github.com/Semester-ly/Freethyme into …
RosaGao Apr 3, 2022
378c033
fix merge conflicts
RosaGao Apr 3, 2022
f3a3215
add event type
RosaGao Apr 8, 2022
a0a159f
fix event type
RosaGao Apr 8, 2022
7d87575
add module file for schedule selector
RosaGao Apr 8, 2022
8d6f7f6
fix event type issue
K02D Apr 12, 2022
ebd1a8d
Merge branch 'feature/calendar-rosa' of https://github.com/Semester-l…
K02D Apr 12, 2022
b06ec40
fix meeting not fetched if page refreshed
K02D Apr 12, 2022
fd8475b
get id from url and update store meetingId
K02D Apr 12, 2022
ab19828
check whether new or returning member
RosaGao Apr 14, 2022
4504cc8
dispatch selected members to show their timeSlots
RosaGao Apr 14, 2022
8e7db90
display red/green/gray for diff cell status
RosaGao Apr 14, 2022
6e9693c
add more to state for easy info sharing
RosaGao Apr 14, 2022
f63b388
fix infinite rendering in Calendar useEffect
RosaGao Apr 14, 2022
97aa678
Show different shades based on number of members
K02D Apr 16, 2022
b9ee5ea
Change slot opacity based on number of members
K02D Apr 16, 2022
b1483b1
Link copied prompt disappears after a delay
K02D Apr 17, 2022
e2b776b
Delete member functionality
K02D Apr 23, 2022
e44e298
Validation for blank member name
K02D Apr 23, 2022
f75552d
Delete button validation
K02D Apr 23, 2022
1d5527a
Enhance meeting name styling
K02D Apr 23, 2022
78fdd19
Stop execution if blank name
K02D Apr 23, 2022
765f811
Show members in slot on hover
K02D Apr 23, 2022
cbe211d
Add select all members button
K02D Apr 23, 2022
7e2514a
Add edit functionality and further validation
K02D Apr 24, 2022
10e1a10
Fix bug so times get updated correctly
K02D Apr 24, 2022
c267a62
guard against duplicate names
K02D Apr 24, 2022
34a0eb5
clear grid when 0 members selected
K02D Apr 24, 2022
2c8655e
Fix bugs so new members can be added
K02D Apr 24, 2022
541875d
Show updated times without page refresh
K02D Apr 24, 2022
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
834 changes: 798 additions & 36 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.8.2",
"@emotion/styled": "^11.8.1",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@mui/material": "^5.5.2",
"@reduxjs/toolkit": "^1.8.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
Expand All @@ -25,7 +28,7 @@
"react-schedule-selector": "^3.0.0",
"react-scripts": "5.0.0",
"sass": "^1.49.9",
"styled-components": "^5.3.3",
"styled-components": "^5.3.5",
"typescript": "~4.1.5",
"uuid": "^8.3.2"
},
Expand All @@ -49,5 +52,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/react-copy-to-clipboard": "^5.0.2"
}
}
10 changes: 7 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import Landing from './pages/Landing';
import Schedule from './pages/Schedule';
import Meeting from './pages/Meeting';
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

function App() {




return (
<>
<Router>
<Routes>
<Route path="/" element={<Landing />} />
<Route path="/create" element={<Schedule />} />
<Route path="/" element={<Landing />} />
<Route path="/:id" element={<Meeting />}>

</Route>
</Routes>
</Router>
</>
Expand Down
107 changes: 107 additions & 0 deletions src/api/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import axios from "axios";
import { store } from "../app/store";
import { setCurMemberSlots, updateMemberSlots } from "../pages/meetingSlice";

const axiosInstance = axios.create({
baseURL: "http://localhost:4000",
});

async function createMeeting(meetingName) {
try {
const response = await axiosInstance.post(`/api/calendars`, {name: meetingName});
return response.data;
// {
// "id": integer,
// "name": string,
// "members": []
// }
} catch(err) {
console.log(err);
}
}

async function getMeeting(meetingId) {
try{
const response = await axiosInstance.get(`/api/calendars/${meetingId}`);
return response.data;
// {
// "id": integer, (meetingId)
// "name": string,
// "members": list[Member]
// }
} catch(err){
console.log(err)
}
}

async function renameMeeting(meetingId, newName) {
try{
const response = await axiosInstance.patch(`/api/calendars/${meetingId}`, {name:newName});
return response.data;
// {
// "id": integer, (meetingId)
// "name": string,
// "members": list[Member]
// }
} catch(err){
console.log(err)
}
}

async function addNewMember(meetingId, memberName) {
try {
const response = await axiosInstance.post(`/api/calendars/${meetingId}/members/`, {name: memberName});
return response.data;
// {
// "id": integer,
// "name": string,
// "timeSlots": []
// }
} catch(err) {
console.log(err);
}
}

async function setAvail(meetingId, memberId, timeSlots) {
try {
store.dispatch(setCurMemberSlots(timeSlots))
const response = await axiosInstance.put(`/api/calendars/${meetingId}/members/${memberId}`, { timeSlots });
store.dispatch(updateMemberSlots({id: memberId, name: response.data.name, timeSlots: timeSlots }))
return response.data;
// {
// "id": integer
// "name": string
// "timeSlots": list[TimeSlot]
// }
} catch(err) {
console.log(err);
}
}

// don't use, member name unique
async function renameMember(meetingId, memberId, newName) {
try{
const response = await axiosInstance.patch(`/api/calendars/${meetingId}/members/${memberId}`, {name:newName});
return response.data;
// {
// "id": integer,
// "name": string,
// "timeSlots": list[TimeSlot]
// }
} catch(err){
console.log(err)
}
}


async function removeMember(meetingId, memberId) {
try{
await axiosInstance.delete(`/api/calendars/${meetingId}/members/${memberId}`);
} catch(err) {
console.log(err);
}

}

export { createMeeting, getMeeting, removeMember, renameMeeting, renameMember, addNewMember, setAvail };

44 changes: 44 additions & 0 deletions src/api/dateFormateConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { TimeSlotType } from "../components/TimeSlot"

export function convertTStoDate(slots: TimeSlotType[]){
const dayMap : any = {"Sunday":0, "Monday":1, "Tuesday":2, "Wednesday":3, "Thursday":4, "Friday":5, "Saturday":6} as Object
const present = new Date();
const currYear = present.getFullYear();
let currDayOfMonth = present.getDate();
let currWeekday = present.getDay();
const currMonth = present.getMonth()
let converted = [] as Date[]
// need to extract hours from no of mins
slots.forEach(slot => {
let daysToAdd;
let slotDay = dayMap[slot.day] as number
daysToAdd = slotDay - currWeekday
// 1410 becomes 23.5
let hourFloat = slot.timeStart/60
let hour = Math.floor(hourFloat)
let minutes = 60 * (hourFloat % 1) // 30 or 0
converted.push(new Date(currYear, currMonth, currDayOfMonth + daysToAdd, hour, minutes))
});
return converted
}

export function convertDatetoTS(dates: Date[], meetingId:number, memberId:number ) {
const timeData = dates.map((date: Date)=>{
const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date);
// "Saturday 23:30"
const [day, time] = formattedDate.split(" ");
const [hour, minute] = time.split(":");
const timeStart = parseInt(hour) * 60 + parseInt(minute);
const timeEnd = timeStart + 30;
const data = {
id : meetingId,
memberId,
day,
timeStart,
timeEnd
};
return data;
});
return timeData
}

4 changes: 2 additions & 2 deletions src/app/store.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import meetingNameReducer from '../pages/meetingNameSlice';
import meetingReducer from '../pages/meetingSlice';


export const store = configureStore({
reducer: {
meetingName: meetingNameReducer
meeting: meetingReducer
},
});

Expand Down
80 changes: 80 additions & 0 deletions src/components/Add.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { addMember, selectMembers, setCurMemberId, setCurMemberName, setCurMemberSlots } from "../pages/meetingSlice";
import { useAppDispatch, useAppSelector } from "../app/hooks";
import * as API from "../api/api";
import { useState } from "react";
import { TextField } from '@material-ui/core';
import { TimeSlotType } from "./TimeSlot";

const Add = () => {
const dispatch = useAppDispatch();
const [memberName, setMemberName] = useState("");
const meetingId = useAppSelector(state => state.meeting.id);
const members = useAppSelector(state => state.meeting.members);
const memberSlots = useAppSelector(state => state.meeting.curMemberSlots);
const selectedMembers = useAppSelector(state => state.meeting.selectedMembers);


const addMemberName = (event: any) => {
const element = event.currentTarget as HTMLInputElement;
setMemberName(element.value);
};

const handleSubmit = async (event: any) => {
event.preventDefault();
// treat "A" the same as "A "
const trimmedName = memberName.trim()
if (trimmedName === "") {
alert("Name can't be blank!");
return;
}
if (selectedMembers.length !== 0) {
alert("Unselect all members to add new availability!")
return;
}
for (let i = 0; i < members.length; i++) {
if (members[i].name === trimmedName) {
alert("Member with this name already exists!");
return;
}
}

// new member

let data = await API.addNewMember(meetingId, trimmedName);
console.log("create new member")
dispatch(setCurMemberId(data.id));
dispatch(setCurMemberName(data.name));
dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots }));

// memberId is undefined in slots at this point
const memberSlotsWithId = memberSlots.map((slot: TimeSlotType) => {
return {...slot, memberId: data.id}
})

API.setAvail(meetingId, data.id, memberSlotsWithId)

};

return (
<div className = "row">
<div className="col" style={{padding: "40px"}}>
<TextField
placeholder="New member name"
value={memberName}
onChange={addMemberName}
/>
</div>
<div className="col">
<button
type="submit"
className="btn btn--add btn__text"
onClick={handleSubmit}
>
Add
</button>
</div>
</div>
)
}

export default Add;
29 changes: 29 additions & 0 deletions src/components/AddAvail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as API from "../api/api";


async function addAvail(meetingId: number, memberId: number, timeSlots: Array<Date>) {

if (meetingId && memberId && timeSlots.length !== 0) {
const timeData = timeSlots.map((date: Date)=>{
const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date);
// "Saturday 23:30"
const [day, time] = formattedDate.split(" ");
const [hour, minute] = time.split(":");
const timeStart = parseInt(hour) * 60 + parseInt(minute);
const timeEnd = timeStart + 30;
const data = {
id : meetingId,
memberId,
day,
timeStart,
timeEnd
};
return data;
});
await API.setAvail(meetingId, memberId, timeData);
console.log("set member availability succeeded");
}

}

export { addAvail };
13 changes: 13 additions & 0 deletions src/components/Available.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { useAppSelector } from '../app/hooks';
const Available = () => {
const members = useAppSelector(state => state.meeting.hoveredMembers)

return (
<div style = {{marginTop: "0%", marginLeft: "-170%", fontSize: "20px", fontFamily: "cursive"}}>
Available members: {members.join(", ")}
</div>
)
}

export default Available;
Loading