Skip to content

Commit

Permalink
Tacs 37 schedule detail (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
Leanz652 authored May 9, 2023
2 parents bd0421a + 53db88f commit ff8e020
Show file tree
Hide file tree
Showing 17 changed files with 632 additions and 109 deletions.
2 changes: 2 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"preview": "vite preview"
},
"dependencies": {
"bootstrap": "^5.2.3",
"react": "^18.2.0",
"react-bootstrap": "^2.7.4",
"react-dom": "^18.2.0",
"react-router-dom": "^6.10.0",
"swr": "^2.1.5"
Expand Down
9 changes: 8 additions & 1 deletion web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { ErrorPage, LoginPage, HomePage } from "./pages";
import { EventDetails } from "./pages/EventDetail/EventDetails";

const router = createBrowserRouter([
{
Expand All @@ -8,7 +9,13 @@ const router = createBrowserRouter([
}
,
{
path: '/', element: <HomePage/>
path: '/', element: <HomePage/>,
children: [
{
path: "/:id",
element: <EventDetails />,
},
],
}
,
{
Expand Down
30 changes: 30 additions & 0 deletions web/src/api/models/dataApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,33 @@ export interface HourRequest {
hour: number
minute: number
}

//INTERFACE TO FETCH AN EVENT WITH AN ID
export interface EventWrapper {
data: Event
}


//INTERFACE TO VOTE
export interface optionVote {
date: string
hour: number
minute: number
}

export interface VoteRequest {
username: string
option: optionVote
}


//INTERFACE TO JOIN AN EVENT
export interface JoinRequest {
username: string
}

//INTERFACE TO TOGGLE VOTING
export interface ToggleVotingRequest {
username: string
voting: boolean
}
54 changes: 49 additions & 5 deletions web/src/api/services/eventService.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,61 @@
import { EventRequest } from "../models/dataApi";
import { EventRequest, ToggleVotingRequest, VoteRequest } from "../models/dataApi";

const url = import.meta.env.VITE_URL


export async function addEvent(urlInput: string, { arg }: {arg: EventRequest} ) {
export async function addEvent(urlInput: string, { arg }: { arg: EventRequest }) {

const requestOptions = {
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem('login')}`
},
body: JSON.stringify(arg)
};

return fetch(url + urlInput, requestOptions).then(res => res.json())
}

export async function joinEvent(urlEvent: string, { arg }: { arg: string }) {

const requestOptions = {
method: 'PATCH',
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem('login')}`
},
body: JSON.stringify({username: arg})
};

return fetch(url + `${urlEvent}/relationships/guests`, requestOptions).then(res => res.json())
}

export async function voteOption(urlEvent: string, { arg }: { arg: VoteRequest }) {

const requestOptions = {
method: 'PATCH',
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem('login')}`
},
body: JSON.stringify(arg)
};

return fetch(url + `${urlEvent}/options`, requestOptions).then(res => res.json())
}


export async function toggleVoting(urlEvento: string, { arg }: {arg: ToggleVotingRequest}) {

const requestOptions = {
method: 'PATCH',
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem('login')}`
},
body: JSON.stringify(arg)
};

return fetch(url+urlInput,requestOptions ).then(res => res.json())
}
return fetch(url + `${urlEvento}/voting`, requestOptions).then(res => res.json())
}
33 changes: 21 additions & 12 deletions web/src/api/swrHooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import useSWR from "swr";

interface Token {
email: string;
exp: number;
id: string;
role: string;
username: string;
}

// mock the user api
const userFetcher = async () => {

const data = localStorage.getItem('login')
if (data) {
// authorized
return data
}

// not authorized
const error = new Error("Not authorized!");
throw error;
};

const data = localStorage.getItem('login')
if (data) {

const decodedToken: Token = JSON.parse(atob(data.split('.')[1])); // Decodifica los datos del token
return decodedToken
}

// not authorized
const error = new Error("Not authorized!");
throw error;
};


export default function useUser() {
const { data, mutate, error } = useSWR<string | null>("/users/me", userFetcher);
const { data, mutate, error } = useSWR<Token | null>("/users/me", userFetcher);

const loading = !data && !error;
const loggedOut = error && error.status === 403;
Expand Down
18 changes: 9 additions & 9 deletions web/src/components/Events/AvailableEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ export const AvailableEvent = () => {
const { events, error, isLoading } = useEvent();


if (error) return "error";
if (isLoading) return "cargando"

return (
<section className={classes.event}>
if (error) return <div>error</div>;
if (isLoading) return <div>loading</div>;
if (!events?.data) {
<div>Aún no hay eventos!</div>
}

return ( <section className={classes.event}>
<Card>
<ul>
{events!.data.map((event: any) => (
<EventItem
key={event.id}
id={event.id}
name={event.description}
description={event.description}
event={event}
></EventItem>
))}
</ul>
</Card>
</section>
);
)
};
100 changes: 68 additions & 32 deletions web/src/components/Events/EventForm.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { useRef } from "react";
import { Button, Modal } from "../UI";
import { useState } from 'react';

import classes from "./EventForm.module.css";
import { FormEvent } from "react";
import { EventRequest } from "../../api/models/dataApi";
import { EventRequest, optionVote } from "../../api/models/dataApi";
import useSWRMutation from "swr/mutation";
import { addEvent } from "../../api/services/eventService";
import useUser from "../../api/swrHooks/useUser";

interface eventFormProps {
onClose: () => any;
onClose: () => void;
}

const today = new Date().toISOString().split("T")[0];
Expand All @@ -17,35 +19,62 @@ export const EventForm = (props: eventFormProps) => {
const nameInput = useRef<HTMLInputElement>(null);
const descInput = useRef<HTMLTextAreaElement>(null);
const placeInput = useRef<HTMLInputElement>(null);
const dateInput = useRef<HTMLInputElement>(null);
const hourInput = useRef<HTMLInputElement>(null);

const { trigger } = useSWRMutation("scheduler-service/schedules", addEvent);
const { user } = useUser();

const [date, setDate] = useState<string>(today);
const [hour, setHour] = useState<string>("");
const [counterOptions, setCounterOptions] = useState<number>(1);

const confirmHandler = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();

const [hours, minutes] = hourInput.current!.value.split(":");
const formData = new FormData(event.currentTarget);
const formFields: {}[] = [];
const optionsToSend: optionVote[] = [];

Object.entries(Object.fromEntries(formData)).forEach((e) => {
formFields.push(e);
});


for(let i = 0; i < (formFields.length)/2; i++) {
const date: string = formFields[i*2][1];
const [hours, minutes] = formFields[(i*2+1)][1].split(":");
optionsToSend.push({date, hour: +hours, minute: +minutes})
}

const newEvent: EventRequest = {
description: descInput.current!.value,
location: placeInput.current!.value,
organizer: "",
organizer: user!.username,
title: nameInput.current!.value,
options: [
{ date: dateInput.current!.value, hour: +hours, minute: +minutes },
],
options: optionsToSend,
guests: [],
};

try {
await trigger(newEvent);
props.onClose()
} catch (e) {
console.log(e);
}
};

const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDate(e.target.value);
};

const handleHourChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHour(e.target.value);
};

const addOption = () => {
setCounterOptions(counterOptions + 1);
setDate(today);
setHour("");
};

return (
<Modal onClose={props.onClose}>
<h3 className=" text-center ">CREA TU EVENTO</h3>
Expand Down Expand Up @@ -89,28 +118,35 @@ export const EventForm = (props: eventFormProps) => {
/>
</div>

<div className="d-flex gap-4">
<div className={classes.control}>
<label htmlFor="dateEvent">
Fecha<span>(*)</span>
</label>
<input
ref={dateInput}
type="date"
id="dateEvent"
min={today}
defaultValue={today}
required
/>
</div>
<div className={classes.control}>
<label htmlFor="hourEvent">
Hora<span>(*)</span>
</label>
<input type="time" id="hourEvent" ref={hourInput} required />
</div>
</div>

{Array.from(Array(counterOptions).keys()).map((i) => {
return (
<div className="d-flex gap-4" key={i}>
<div className={classes.control}>
<label htmlFor="dateEvent">
Fecha<span>(*)</span>
</label>
<input
name={`eventDate${i}`}
type="date"
id="dateEvent"
min={today}
defaultValue={today}
required
onChange={(e) => {handleDateChange(e)}}
/>
</div>
<div className={classes.control}>
<label htmlFor="hourEvent">
Hora<span>(*)</span>
</label>
<input type="time" id="hourEvent" required name={`eventTime${i}`} onChange={(e) => {handleHourChange(e)}} />
</div>

{(i === counterOptions - 1 && date !== "" && hour !== "") && <Button onClick={() => {addOption()}}>+</Button>}
</div>
);
})
}
<Button type="submit"> Crear Evento </Button>
</form>
</Modal>
Expand Down
10 changes: 0 additions & 10 deletions web/src/components/Events/EventItem/CalendarEvent.module.css

This file was deleted.

15 changes: 0 additions & 15 deletions web/src/components/Events/EventItem/CalendarEvent.tsx

This file was deleted.

Loading

0 comments on commit ff8e020

Please sign in to comment.