├── .gitignore ├── README.md ├── eslintrc.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── img │ ├── agenda_peques_logo.svg │ ├── agenda_peques_logo_text.svg │ ├── cat-info.svg │ ├── cat.svg │ ├── events-img.svg │ ├── footerImg.svg │ ├── globe.svg │ ├── img-create-event-2.svg │ ├── img-create-event.svg │ ├── rocket.svg │ ├── sign-up-globe.svg │ └── wireframe.jpg ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt └── src ├── App.css ├── App.test.js ├── components ├── CreateEvents.css ├── EmptyEvents.css ├── EmptyEvents.js ├── Events.css ├── Events.js ├── Footer.css ├── Footer.js ├── Header.css ├── Header.js ├── HeaderDate.css ├── HeaderDate.js ├── Info.css ├── InfoDetailEvent.css ├── ListEvents.css ├── Loading.css ├── Loading.js ├── SignIn.css ├── SignUp.css └── icons │ ├── IconCalendar.js │ ├── IconClock.js │ ├── IconDelete.js │ ├── IconEdit.js │ ├── IconLink.js │ ├── IconLocation.js │ ├── IconReset.js │ ├── IconTarget.js │ └── IconZoomIn.js ├── context └── userContext.js ├── globalStyles.css ├── hooks ├── useField.js └── useUser.js ├── pages ├── _app.js ├── createEvents │ └── [id].js ├── eventDetail │ └── [id].js ├── index.js ├── info.js ├── signIn.js └── signUp.js ├── setupTests.js └── utils ├── api.js ├── localStorage.js ├── tools.js └── tools.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | .env 33 | 34 | # vercel 35 | .vercel 36 | 37 | package-lock.json 38 | yarn.lock 39 | public/workbox-*.js 40 | .prettierignore 41 | .pretierrc.js 42 | .eslintrc.js 43 | .eslintignore 44 | 45 | .next 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIGRATED APP FROM REACT TO NEXTJS 2 | 3 | First,this project was created by ItziarZG and [Marga](https://marga.pro) with [Create React App](https://github.com/facebook/create-react-app). 4 | Then, was migrated to [NEXTJS](https://nextjs.org/) in a live streaming with [@midudev](https://midu.dev/) [here](https://www.twitch.tv/videos/1086611816) 5 | 6 | 7 | ## Getting Started 8 | 9 | First, run the development server: 10 | 11 | ```bash 12 | npm run dev 13 | # or 14 | yarn dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 20 | 21 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 22 | 23 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 24 | 25 | ## Learn More 26 | 27 | To learn more about Next.js, take a look at the following resources: 28 | 29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 31 | 32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 33 | 34 | ## Deploy on Vercel 35 | 36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 37 | 38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 39 | -------------------------------------------------------------------------------- /eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: ["plugin:react/recommended", "standard", "prettier"], 7 | parserOptions: { 8 | ecmaFeatures: { 9 | jsx: true, 10 | }, 11 | ecmaVersion: 12, 12 | sourceType: "module", 13 | }, 14 | plugins: ["react"], 15 | rules: { "react/react-in-jsx-scope": "off", "react/prop-types": "off" }, 16 | }; 17 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src" 4 | } 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://www.agendapequeseivissa.tk/", 3 | "name": "agenda-react", 4 | "version": "0.1.0", 5 | "private": true, 6 | "dependencies": { 7 | "@supabase/supabase-js": "1.15.1", 8 | "@testing-library/jest-dom": "5.14.1", 9 | "@testing-library/react": "11.2.7", 10 | "@testing-library/user-event": "12.8.3", 11 | "next": "^12.0.1", 12 | "react": "^17.0.2", 13 | "react-dom": "17.0.2", 14 | "web-vitals": "1.1.2" 15 | }, 16 | "scripts": { 17 | "dev": "next dev", 18 | "build": "next build", 19 | "start": "next start" 20 | }, 21 | "browserslist": { 22 | "production": [ 23 | ">0.2%", 24 | "not dead", 25 | "not op_mini all" 26 | ], 27 | "development": [ 28 | "last 1 chrome version", 29 | "last 1 firefox version", 30 | "last 1 safari version" 31 | ] 32 | }, 33 | "devDependencies": { 34 | "eslint": "^7.32.0", 35 | "eslint-config-next": "^11.0.1", 36 | "eslint-config-prettier": "^8.3.0", 37 | "eslint-config-standard": "^16.0.3", 38 | "eslint-plugin-import": "^2.23.4", 39 | "eslint-plugin-node": "^11.1.0", 40 | "eslint-plugin-promise": "^5.1.0", 41 | "eslint-plugin-react": "^7.24.0", 42 | "prettier": "^2.3.2" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itziarZG/agenda-react/6436ea87ca1494e804b27cf8f95a7dfcaa60dc33/public/favicon.ico -------------------------------------------------------------------------------- /public/img/agenda_peques_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /public/img/agenda_peques_logo_text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | agenda 53 | 54 | 55 | peques 56 | 57 | 58 | -------------------------------------------------------------------------------- /public/img/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/img/rocket.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/img/sign-up-globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/img/wireframe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itziarZG/agenda-react/6436ea87ca1494e804b27cf8f95a7dfcaa60dc33/public/img/wireframe.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 17 | 23 | 24 | 25 | 29 | 30 | 39 | Agenda Peques Eivissa 40 | 41 | 42 | 43 |
44 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itziarZG/agenda-react/6436ea87ca1494e804b27cf8f95a7dfcaa60dc33/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itziarZG/agenda-react/6436ea87ca1494e804b27cf8f95a7dfcaa60dc33/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | /* .App { 2 | text-align: center; 3 | } */ 4 | html{ 5 | scroll-behavior: smooth; 6 | } -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/components/CreateEvents.css: -------------------------------------------------------------------------------- 1 | .form_event { 2 | max-width: 384px; 3 | width: 80%; 4 | margin: auto; 5 | padding-bottom: 20px; 6 | } 7 | 8 | .reset-Info-createEvent { 9 | background-color: var(--white); 10 | fill: var(--primary); 11 | padding: 2px 3px; 12 | border-radius: 100%; 13 | font-weight: bold; 14 | font-size: 20px; 15 | width: 40px; 16 | height: 40px; 17 | box-shadow: 3px 3px 6px var(--gray-600); 18 | /* border: 2px solid var(--primary); */ 19 | margin-top: 20px; 20 | position: fixed; 21 | /* top: 100px; */ 22 | right: 30px; 23 | cursor: pointer; 24 | appearance: none; 25 | -webkit-appearance: none; 26 | -moz-appearance: none; 27 | text-decoration: none; 28 | } 29 | 30 | .reset-Info-createEvent:hover { 31 | fill: var(--white); 32 | background-color: var(--primary); 33 | box-shadow: 5px 5px 6px var(--gray-600); 34 | } 35 | 36 | .create-event-box { 37 | margin-top: 20px; 38 | height: calc(100vh - 185px); 39 | overflow: auto; 40 | } 41 | 42 | .create_event_title { 43 | text-align: left; 44 | color: var(--primary); 45 | font-size: 18px; 46 | font-weight: 700; 47 | margin-top: 20px; 48 | } 49 | 50 | .event_form { 51 | display: flex; 52 | flex-direction: column; 53 | align-items: flex-start; 54 | } 55 | 56 | .event_form_input { 57 | max-width: 384px; 58 | width: 100%; 59 | font-size: 16px; 60 | font-family: inherit; 61 | font-weight: 400; 62 | line-height: 24px; 63 | box-sizing: border-box; 64 | padding: 10px 16px; 65 | outline: none; 66 | border-radius: 8px; 67 | border: none; 68 | appearance: none; 69 | color: var(--black-200); 70 | background-color: var(--gray-200); 71 | margin-bottom: 2px; 72 | 73 | } 74 | .event_form_input_file::-webkit-file-upload-button { 75 | visibility: hidden; 76 | } 77 | .event_form_input_file:before { 78 | content: 'Busca el archivo'; 79 | display: inline-block; 80 | background: linear-gradient(top, #f9f9f9, #e3e3e3); 81 | border: 1px solid #999; 82 | color: var(--gray-800); 83 | border-radius: 3px; 84 | padding: 5px 8px; 85 | outline: none; 86 | white-space: nowrap; 87 | user-select: none; 88 | cursor: pointer; 89 | text-shadow: 1px 1px #fff; 90 | font-weight: 700; 91 | font-size: 10pt; 92 | } 93 | .event_form_input_file:hover::before { 94 | 95 | border-color: black; 96 | } 97 | .event_form_inputactive_file:active::before { 98 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9); 99 | } 100 | .event_form_input_number{ 101 | width: 50%; 102 | } 103 | 104 | .event_form_label { 105 | margin: 14px 0 4px; 106 | color: var(--black-200); 107 | font-size: 14px; 108 | font-weight: 700; 109 | } 110 | 111 | .event_btn { 112 | margin-top: 20px; 113 | max-width: 384px; 114 | width: 100%; 115 | padding: 10px 16px; 116 | cursor: pointer; 117 | border: none; 118 | background: var(--primary); 119 | color: var(--white); 120 | border-radius: 8px; 121 | appearance: none; 122 | position: relative; 123 | outline: none; 124 | font-size: 14px; 125 | font-weight: 700; 126 | line-height: 20px; 127 | height: 40px; 128 | } 129 | 130 | .event_btn:disabled { 131 | opacity: 0.5; 132 | } 133 | 134 | .event_btn:disabled:hover { 135 | opacity: 0.5; 136 | } 137 | 138 | .event_btn:hover { 139 | opacity: 0.7; 140 | } 141 | 142 | @media screen and (min-width: 750px) { 143 | .create-event-box { 144 | display: flex; 145 | } 146 | .box-create-event-img { 147 | width: 30%; 148 | } 149 | .form_event { 150 | width: 70%; 151 | } 152 | .create-event-img { 153 | width: 25%; 154 | height: 100vh; 155 | background-image: url("/img/img-create-event-2.svg"); 156 | background-repeat: no-repeat; 157 | background-position: center; 158 | border-radius: 20px; 159 | margin-left: 10%; 160 | position: fixed; 161 | opacity: 0.7; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/components/EmptyEvents.css: -------------------------------------------------------------------------------- 1 | .empty_events_container { 2 | width: 100vw; 3 | height: 85vh; 4 | /* background: var(--gray-500); */ 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | p{ 10 | color: var(--gray-800); 11 | font-size: 16px; 12 | font-weight: 700; 13 | width: 200px; 14 | line-height: 1.5; 15 | } 16 | .loading_img { 17 | height: 30%; 18 | } 19 | 20 | .eyes-empty { 21 | fill: var(--white); 22 | } 23 | 24 | .eyes { 25 | fill: var(--black); 26 | animation-name: empty; 27 | animation-duration: 2s; 28 | animation-iteration-count: infinite; 29 | } 30 | 31 | .eyes-Agenda { 32 | fill: white; 33 | } 34 | 35 | @keyframes empty { 36 | 0% { 37 | fill: var(--black); 38 | } 39 | 50% { 40 | fill: var(--black); 41 | } 42 | 100% { 43 | fill: var(--white); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/components/EmptyEvents.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const EmptyEvents = () => { 4 | return ( 5 |
6 | 23 | 24 | 28 | 29 | 30 | 37 | 38 | 39 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 59 | 60 | 61 | 68 | 69 | 70 | 77 | 78 | 79 | 86 | 87 | 88 | 95 | 96 | 97 | 104 | 105 | 106 | 113 | 114 | 115 | 122 | 123 | 124 | 131 | 132 | 133 | 140 | 141 | 146 | 150 | 151 | 152 | 153 |

Els events ja han passat. Afegeix un nou!

154 |
155 | ); 156 | }; 157 | 158 | export default EmptyEvents; 159 | -------------------------------------------------------------------------------- /src/components/Events.css: -------------------------------------------------------------------------------- 1 | .event_title { 2 | font-size: 16px; 3 | font-weight: 700; 4 | /* max-width: 150px; */ 5 | overflow: auto; 6 | text-align: left; 7 | line-height: 20px; 8 | } 9 | .eventsTime { 10 | height: 540px; 11 | } 12 | 13 | .event_date { 14 | font-size: 14px; 15 | color: var(--gray-800); 16 | font-weight: bold; 17 | } 18 | .event_date::after{ 19 | content: "h"; 20 | display: inline-block; 21 | 22 | } 23 | 24 | .event { 25 | width: 90%; 26 | margin: auto; 27 | padding: 10px 10px 25px 10px; 28 | display: flex; 29 | flex-direction: row; 30 | align-items: flex-start; 31 | justify-content: flex-start; 32 | /* box-shadow: #d1d9e6 2px 2px 5px; */ 33 | /* cursor: pointer; */ 34 | } 35 | 36 | /* .event:hover { 37 | box-shadow: #d1d9e6 5px 5px 10px; 38 | } */ 39 | 40 | .event_box_1 { 41 | display: flex; 42 | width: 70%; 43 | overflow-wrap: break-word; 44 | word-wrap: break-word; 45 | } 46 | 47 | .more_delete_btns { 48 | display: flex; 49 | justify-content: flex-end; 50 | align-items: flex-end; 51 | /* background-color: blueviolet; */ 52 | margin-top: 25px; 53 | } 54 | 55 | .icon_delete { 56 | /* width: 20px; */ 57 | width: 25px; 58 | margin-left: 5px; 59 | fill: var(--gray-800); 60 | cursor: pointer; 61 | } 62 | 63 | .icon_edit { 64 | /* width: 20px; */ 65 | width: 25px; 66 | margin-left: 25px; 67 | fill: var(--gray-800); 68 | cursor: pointer; 69 | } 70 | 71 | .icon_edit:hover { 72 | fill: var(--primary); 73 | } 74 | 75 | .icon_delete:hover { 76 | fill: var(--primary); 77 | } 78 | 79 | .event_box_2 { 80 | display: flex; 81 | flex-direction: column; 82 | align-items: flex-end; 83 | /* justify-content: space-between; */ 84 | width: 30%; 85 | /* background-color: brown; */ 86 | } 87 | 88 | .event_img { 89 | width: 70px; 90 | height: 70px; 91 | object-fit: cover; 92 | border-radius: 10%; 93 | margin-right: 10px; 94 | } 95 | 96 | .more_info { 97 | color: var(--white); 98 | font-weight: 700; 99 | padding: 3px 12px; 100 | cursor: pointer; 101 | border: none; 102 | text-decoration: none; 103 | color: var(--primary); 104 | background-color: var(--white); 105 | border-radius: 6px; 106 | -webkit-appearance: none; 107 | appearance: none; 108 | outline: none; 109 | font-size: 14px; 110 | line-height: 20px; 111 | height: 28px; 112 | margin-top: 20px; 113 | opacity: 0.7; 114 | box-shadow: #d1d9e6 2px 2px 5px; 115 | } 116 | 117 | .more_info:hover { 118 | color: var(--white); 119 | background: var(--primary); 120 | } 121 | 122 | @media screen and (min-width: 750px) { 123 | .events { 124 | width: 500px; 125 | margin: auto; 126 | } 127 | 128 | .event_title { 129 | max-width: 300px; 130 | } 131 | } 132 | 133 | @media screen and (min-width: 1000px) { 134 | .eventsTime { 135 | display: flex; 136 | width: 100%; 137 | justify-content: center; 138 | } 139 | 140 | .event_list_1 { 141 | width: 100%; 142 | margin-right: 0; 143 | } 144 | 145 | .event_list_2 { 146 | /* background-color: green; */ 147 | width: 30%; 148 | height: calc(100vh - 140px); 149 | } 150 | 151 | .events { 152 | /* width: 65%; */ 153 | width: 50%; 154 | margin: 0; 155 | } 156 | 157 | .event_img { 158 | width: 100px; 159 | height: 100px; 160 | object-fit: cover; 161 | border-radius: 10%; 162 | margin-right: 10px; 163 | } 164 | 165 | .event_title { 166 | max-width: 300px; 167 | font-size: 18px; 168 | } 169 | 170 | .event_date { 171 | font-size: 16px; 172 | } 173 | 174 | .img-globe-box2 { 175 | width: 100%; 176 | height: 100%; 177 | background-image: url("/img/globe.svg"); 178 | background-repeat: no-repeat; 179 | background-position: center; 180 | margin: 0 55px; 181 | 182 | margin-left: 0; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/components/Events.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useRouter } from "next/router"; 3 | import Link from "next/link"; 4 | 5 | import api from "../utils/api"; 6 | 7 | import HeaderDate from "./HeaderDate.js"; 8 | import IconDelete from "./icons/IconDelete.js"; 9 | 10 | const Events = ({ events, date, userId }) => { 11 | const history = useRouter(); 12 | 13 | async function deleteEvents(id) { 14 | await api.deleteEvent(id); 15 | window.location.reload() 16 | } 17 | 18 | return ( 19 |
20 | 21 | {events[date].map((ev) => { 22 | // const time = ev.hour ? ev.hour.slice(0, -3) + "h" : null; 23 | return ( 24 |
25 |
26 | {ev.name} 27 |

{ev.title}

28 |
29 |
30 |
{ev.hour}
31 |
32 | {userId === ev.user_id && ( 33 |
34 | {/* 35 | 36 | 37 | 38 | */} 39 | deleteEvents(ev.id)}> 40 | 41 | 42 |
43 | )} 44 |
45 | 46 | Info 47 | 48 |
49 |
50 | ); 51 | })} 52 |
53 | ); 54 | }; 55 | 56 | export default Events; 57 | -------------------------------------------------------------------------------- /src/components/Footer.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | -webkit-box-sizing: border-box; 6 | } 7 | 8 | .footer { 9 | width: 100%; 10 | height: 75px; 11 | padding: 30px 10px 50px; 12 | display: flex; 13 | flex-direction: row; 14 | align-items: center; 15 | justify-content: center; 16 | position: fixed; 17 | bottom: 0; 18 | } 19 | 20 | .footer_logo { 21 | width: 100px; 22 | height: 30px; 23 | background-image: url("/img/agenda_peques_logo_text.svg"); 24 | background-repeat: no-repeat; 25 | background-position: start; 26 | } 27 | 28 | .footer_box1 { 29 | width: 30%; 30 | height: 70px; 31 | display: flex; 32 | flex-direction: column; 33 | align-items: flex-start; 34 | justify-content: space-around; 35 | z-index: 1; 36 | } 37 | 38 | .footer_box2 { 39 | width: 70%; 40 | height: 65px; 41 | font-size: 12px; 42 | color: var(--gray-800); 43 | text-align: end; 44 | display: flex; 45 | flex-direction: column; 46 | align-items: flex-end; 47 | justify-content: space-around; 48 | z-index: 1; 49 | } 50 | 51 | .copyright { 52 | font-size: 14px; 53 | color: var(--gray-800); 54 | } 55 | 56 | .footer_mail { 57 | font-size: 12px; 58 | color: var(--gray-800); 59 | font-weight: bold; 60 | } 61 | 62 | .footer_authors { 63 | font-weight: bold; 64 | } 65 | 66 | a { 67 | text-decoration: none; 68 | color: var(--gray-800); 69 | } 70 | 71 | .footer_detail { 72 | width: 100%; 73 | height: 45px; 74 | background-image: url("/img/footerImg.svg"); 75 | background-repeat: repeat; 76 | background-position: right; 77 | position: fixed; 78 | bottom: 0; 79 | left: 0; 80 | opacity: 0.3; 81 | margin: 0; 82 | padding: 0; 83 | } 84 | 85 | .footer_info { 86 | font-weight: 700; 87 | cursor: pointer; 88 | color: var(--primary); 89 | font-size: 14px; 90 | z-index: 5; 91 | cursor: pointer; 92 | } 93 | 94 | .footer_info:hover { 95 | font-weight: 700; 96 | padding: 3px 12px; 97 | cursor: pointer; 98 | border: none; 99 | text-decoration: none; 100 | color: var(--primary); 101 | background-color: var(--white); 102 | border-radius: 6px; 103 | -webkit-appearance: none; 104 | appearance: none; 105 | outline: none; 106 | font-size: 14px; 107 | line-height: 20px; 108 | height: 28px; 109 | margin-top: 20px; 110 | opacity: 0.7; 111 | box-shadow: #d1d9e6 2px 2px 5px; 112 | } 113 | 114 | @media screen and (min-width: 1200px) { 115 | .footer { 116 | padding-left: 100px; 117 | padding-right: 100px; 118 | } 119 | 120 | .footer_detail { 121 | width: 100%; 122 | height: 50px; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from 'next/link' 3 | 4 | const Footer = (props) => { 5 | return ( 6 |
7 |
8 |
9 | 10 |

© 2021

11 | 12 | {" "} 13 | + info 14 | 15 |
16 | 17 |
18 |

19 | Design by{" "} 20 | 21 | Marga Martinez 22 | 23 |

24 |

25 | Created by ItziarZG & Marga 26 |

27 | 28 |

agendapequeseivissa@gmail.com

29 |
30 |
31 |
32 | ); 33 | }; 34 | 35 | export default Footer; 36 | -------------------------------------------------------------------------------- /src/components/Header.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | -webkit-box-sizing: border-box; 6 | } 7 | 8 | .header { 9 | width: 100%; 10 | height: 100px; 11 | padding: 20px 30px; 12 | display: flex; 13 | justify-content: flex-end; 14 | align-items: center; 15 | border-bottom: var(--gray-200) 1px solid; 16 | margin: auto; 17 | } 18 | 19 | .header_create_event { 20 | margin-right: 10px; 21 | } 22 | 23 | .header_log_out { 24 | /* box-shadow: #d1d9e6 2px 2px 5px; */ 25 | margin-right: 10px; 26 | padding: 10px 16px; 27 | cursor: pointer; 28 | border: none; 29 | color: var(--primary); 30 | background: var(--white); 31 | border-radius: 8px; 32 | outline: none; 33 | font-size: 14px; 34 | font-weight: 700; 35 | line-height: 20px; 36 | /* height: 40px; */ 37 | } 38 | 39 | .header_log_out:hover { 40 | box-shadow: #d1d9e6 5px 5px 10px; 41 | } 42 | 43 | .avatar { 44 | width: 30px; 45 | margin-right: 10px; 46 | } 47 | .header_logo_container { 48 | margin-right: auto; 49 | } 50 | 51 | .header_logo { 52 | width: 40px; 53 | height: 40px; 54 | background-image: url("/img/agenda_peques_logo.svg"); 55 | background-repeat: no-repeat; 56 | background-position: center; 57 | } 58 | 59 | .header_signIn { 60 | margin-right: 10px; 61 | } 62 | 63 | .btn { 64 | padding: 10px 16px; 65 | cursor: pointer; 66 | border: 1px solid var(--primary); 67 | background: var(--primary); 68 | color: var(--white); 69 | border-radius: 8px; 70 | outline: none; 71 | font-size: 14px; 72 | font-weight: 700; 73 | line-height: 20px; 74 | /* height: 40px; */ 75 | } 76 | 77 | .btn:hover { 78 | opacity: 0.7; 79 | } 80 | 81 | .header_signUp { 82 | background: var(--white); 83 | color: var(--primary); 84 | } 85 | .header_link{ 86 | color: var(--primary); 87 | font-size: 14px; 88 | font-weight: 700; 89 | line-height: 20px; 90 | margin-left: 6px 91 | } 92 | 93 | @media screen and (min-width: 410px) { 94 | .header_logo { 95 | width: 120px; 96 | height: 120px; 97 | background-image: url("/img/agenda_peques_logo_text.svg"); 98 | background-repeat: no-repeat; 99 | background-position: center; 100 | } 101 | } 102 | 103 | @media screen and (min-width: 1200px) { 104 | .header { 105 | padding-left: 100px; 106 | padding-right: 100px; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | import { useRouter } from "next/router"; 2 | import { useContext } from 'react'; 3 | import Link from "next/link"; 4 | import storage from "../utils/localStorage"; 5 | import userContext from "context/userContext"; 6 | 7 | export default function Header() { 8 | const history = useRouter(); 9 | 10 | const { user, setUser } = useContext(userContext) 11 | 12 | function logout() { 13 | setUser({ userId: null }); 14 | storage.wipeUser(); 15 | history.replace("/"); 16 | } 17 | 18 | function renderSign() { 19 | return ( 20 | <> 21 | 22 | Log in 23 | 24 | 25 | Register 26 | 27 | 28 | Info 29 | 30 | 31 | ); 32 | } 33 | 34 | function renderLogueado() { 35 | return ( 36 | <> 37 | 40 | 41 | Crear evento 42 | 43 | 44 | ); 45 | } 46 | 47 | return ( 48 | <> 49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 | {user.length === 0 || user.userId === null ? renderSign() : renderLogueado()} 57 |
58 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /src/components/HeaderDate.css: -------------------------------------------------------------------------------- 1 | .header_date { 2 | width: 90%; 3 | margin: auto; 4 | } 5 | 6 | .header_date_title { 7 | font-size: 20px; 8 | margin-top: 20px; 9 | margin-bottom: 10px; 10 | padding-bottom: 10px; 11 | color: var(--gray-800); 12 | text-align: left; 13 | border-bottom: solid 2px var(--gray-200); 14 | } 15 | 16 | .header_date_day { 17 | color: var(--primary); 18 | font-weight: 800; 19 | font-size: 22px; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/HeaderDate.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const MONTHS = [ 4 | 'Enero', 5 | 'Febrero', 6 | 'Marzo', 7 | 'Abril', 8 | 'Mayo', 9 | 'Junio', 10 | 'Julio', 11 | 'Agosto', 12 | 'Septembre', 13 | 'Octubre', 14 | 'Noviembre', 15 | 'Diciembre', 16 | ]; 17 | 18 | const WEEKDAYS = [ 19 | 'Domingo', 20 | 'Lunes', 21 | 'Martes', 22 | 'Miercoles', 23 | 'Jueves', 24 | 'Viernes', 25 | 'Sabado', 26 | ]; 27 | 28 | const HeaderDate = ({ date }) => { 29 | let dateObject = new Date(date); 30 | let month = MONTHS[dateObject.getMonth()]; 31 | let weekday = WEEKDAYS[dateObject.getDay()]; 32 | let day = dateObject.getDate(); 33 | 34 | return ( 35 |
36 |

37 | {weekday} | {day} de {month} 38 |

39 |
40 | ); 41 | }; 42 | 43 | export default HeaderDate; 44 | -------------------------------------------------------------------------------- /src/components/Info.css: -------------------------------------------------------------------------------- 1 | .info_detail_footer { 2 | width: 100%; 3 | height: 40px; 4 | background-image: url("/img/footerImg.svg"); 5 | background-repeat: repeat; 6 | background-position: right; 7 | position: fixed; 8 | bottom: 40px; 9 | left: 0; 10 | opacity: 0.3; 11 | margin: 0; 12 | padding: 0; 13 | /* mask-image: linear-gradient(to top, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); */ 14 | } 15 | .info__texts { 16 | width: 100%; 17 | height: calc(100vh - 185px); 18 | color: var(--gray-800); 19 | font-size: 16px; 20 | font-weight: 700; 21 | margin-bottom: 10px; 22 | overflow: auto; 23 | padding: 10px; 24 | } 25 | .info__texts__text{ 26 | width: 100%; 27 | } 28 | .info__link { 29 | font-weight: 700; 30 | cursor: pointer; 31 | color: var(--primary); 32 | font-size: 14px; 33 | padding-bottom: 10px; 34 | } 35 | 36 | .info__link:hover { 37 | font-weight: 700; 38 | padding: 3px 12px; 39 | cursor: pointer; 40 | border: none; 41 | text-decoration: none; 42 | color: var(--primary); 43 | background-color: var(--white); 44 | border-radius: 6px; 45 | -webkit-appearance: none; 46 | appearance: none; 47 | outline: none; 48 | font-size: 14px; 49 | line-height: 20px; 50 | height: 28px; 51 | margin-top: 20px; 52 | opacity: 0.7; 53 | box-shadow: #d1d9e6 2px 2px 5px; 54 | } 55 | 56 | .info__line { 57 | width: 100%; 58 | border-bottom: var(--gray-200) 1px solid; 59 | } 60 | .strong{ 61 | font-weight: 700; 62 | color:black 63 | } 64 | @media all and (min-width: 768px) { 65 | .info__texts { 66 | padding: 30px; 67 | display: flex; 68 | flex-direction: column; 69 | align-items: center; 70 | justify-content: space-evenly; 71 | } 72 | } 73 | @media all and (min-width: 1024px) { 74 | .info__link { 75 | font-size: 18px; 76 | } 77 | .info__texts { 78 | padding: 50px; 79 | display: flex; 80 | flex-direction: column; 81 | align-items: center; 82 | justify-content: flex-start; 83 | } 84 | .info__texts__text { 85 | margin: 30px 0; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/components/InfoDetailEvent.css: -------------------------------------------------------------------------------- 1 | .info_detail_container { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 0 20px; 5 | height: calc(100vh - 180px); 6 | overflow: auto; 7 | } 8 | 9 | .info_detail_reset { 10 | background-color: var(--white); 11 | fill: var(--primary); 12 | padding: 2px 3px; 13 | border-radius: 100%; 14 | font-weight: bold; 15 | font-size: 20px; 16 | width: 40px; 17 | height: 40px; 18 | box-shadow: 3px 3px 6px var(--gray-600); 19 | /* border: 2px solid var(--primary); */ 20 | /* margin-top: 20px; */ 21 | align-self: flex-end; 22 | cursor: pointer; 23 | text-decoration: none; 24 | } 25 | 26 | .info_detail_reset:hover { 27 | fill: var(--white); 28 | background-color: var(--primary); 29 | box-shadow: 5px 5px 6px var(--gray-600); 30 | } 31 | 32 | .info_detail { 33 | width: 90%; 34 | max-width: 500px; 35 | margin: auto; 36 | text-align: left; 37 | padding: 10px; 38 | display: flex; 39 | flex-direction: column; 40 | } 41 | 42 | .info_detail_text { 43 | margin: auto; 44 | width: 90%; 45 | } 46 | 47 | .info_detail_date { 48 | margin-bottom: 20px; 49 | } 50 | .info_detail_title { 51 | color: var(--primary); 52 | font-size: 26px; 53 | margin-bottom: 10px; 54 | word-wrap: break-word; 55 | line-height: 28px; 56 | } 57 | 58 | .info_detail_image { 59 | margin-bottom: 20px; 60 | margin-top: 20px; 61 | width: 90%; 62 | height: auto; 63 | border-radius: 20px; 64 | align-self: center; 65 | } 66 | 67 | .info_detail_items_date { 68 | color: var(--black); 69 | font-size: 18px; 70 | font-weight: 700; 71 | margin-bottom: 10px; 72 | line-height: 20px; 73 | word-wrap: break-word; 74 | display: flex; 75 | align-items: center; 76 | } 77 | 78 | .info_detail_items { 79 | color: var(--gray-800); 80 | font-size: 16px; 81 | font-weight: 700; 82 | margin-bottom: 10px; 83 | line-height: 20px; 84 | word-wrap: break-word; 85 | display: flex; 86 | align-items: center; 87 | } 88 | 89 | .icon-text { 90 | color: var(--gray-800); 91 | } 92 | 93 | .icon_calendar { 94 | width: 20px; 95 | fill: var(--gray-800); 96 | margin-right: 10px; 97 | } 98 | 99 | .icon_clock { 100 | width: 20px; 101 | fill: var(--gray-800); 102 | margin-right: 10px; 103 | } 104 | 105 | .icon_items { 106 | width: 18px; 107 | fill: var(--gray-800); 108 | margin-right: 10px; 109 | } 110 | 111 | .icon_info { 112 | width: 80%; 113 | display: -webkit-box; 114 | -webkit-box-orient: vertical; 115 | -webkit-line-clamp: 3; 116 | overflow: hidden; 117 | 118 | } 119 | 120 | .title-items { 121 | color: var(--gray-800); 122 | font-size: 14px; 123 | font-weight: 700; 124 | line-height: 20px; 125 | } 126 | 127 | .info_cat_img { 128 | height: 100px; 129 | background-image: url("/img/cat-info.svg"); 130 | background-repeat: no-repeat; 131 | background-position: right; 132 | margin-top: 10px; 133 | margin-bottom: 20px; 134 | } 135 | 136 | @media screen and (min-width: 750px) { 137 | .info_detail_reset { 138 | align-self: flex-end; 139 | } 140 | 141 | .info_detail { 142 | flex-direction: row; 143 | max-width: 1000px; 144 | align-content: flex-start; 145 | /* margin-top: 30px; */ 146 | } 147 | .info_detail_image { 148 | width: 45%; 149 | align-self: start; 150 | } 151 | .info_detail_text { 152 | margin: auto; 153 | width: 50%; 154 | margin-left: 40px; 155 | } 156 | .info_cat_img { 157 | margin-top: 0px; 158 | } 159 | } 160 | 161 | @media screen and (min-width: 900px) { 162 | .info_cat_img { 163 | height: 150px; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/components/ListEvents.css: -------------------------------------------------------------------------------- 1 | .events { 2 | /* width: 384px; */ 3 | margin: auto; 4 | } 5 | 6 | @media screen and (min-width: 1000px) { 7 | .event_list_1 { 8 | width: 100%; 9 | margin-right: 0; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Loading.css: -------------------------------------------------------------------------------- 1 | .loading_container { 2 | width: 100vw; 3 | height: 85vh; 4 | /* background: var(--gray-500); */ 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | 10 | .loading_img { 11 | /* width: 40%; */ 12 | height: 30%; 13 | } 14 | 15 | .eyes-Agenda { 16 | fill: white; 17 | animation-name: eyes; 18 | animation-duration: 2s; 19 | animation-iteration-count: infinite; 20 | } 21 | 22 | @keyframes eyes { 23 | 0% { 24 | fill: var(--black); 25 | } 26 | 25% { 27 | fill: var(--white); 28 | } 29 | 50% { 30 | fill: var(--black); 31 | } 32 | 100% { 33 | fill: var(--white); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Loading = () => { 4 | return ( 5 |
6 | 19 | 20 | 24 | 25 | 26 | 33 | 34 | 35 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | 62 | 63 | 71 | 72 | 73 | 80 | 81 | 82 | 89 | 90 | 91 | 98 | 99 | 100 | 107 | 108 | 109 | 116 | 117 | 118 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 | ); 133 | }; 134 | 135 | export default Loading; 136 | -------------------------------------------------------------------------------- /src/components/SignIn.css: -------------------------------------------------------------------------------- 1 | *:focus { 2 | outline: none; 3 | } 4 | 5 | .reset_info_signIn { 6 | background-color: var(--white); 7 | fill: var(--primary); 8 | padding: 2px 3px; 9 | border-radius: 100%; 10 | font-weight: bold; 11 | font-size: 20px; 12 | width: 40px; 13 | height: 40px; 14 | box-shadow: 3px 3px 6px var(--gray-600); 15 | /* border: 2px solid var(--primary); */ 16 | margin-top: 20px; 17 | position: fixed; 18 | right: 30px; 19 | cursor: pointer; 20 | appearance: none; 21 | -webkit-appearance: none; 22 | -moz-appearance: none; 23 | text-decoration: none; 24 | } 25 | 26 | .reset_info_signIn:hover { 27 | fill: var(--white); 28 | background-color: var(--primary); 29 | box-shadow: 5px 5px 6px var(--gray-600); 30 | } 31 | 32 | .logo { 33 | width: 100px; 34 | margin-bottom: 10px; 35 | } 36 | 37 | .signIn { 38 | max-width: 384px; 39 | width: 80%; 40 | margin: auto; 41 | margin-top: 70px; 42 | } 43 | 44 | .signIn_form { 45 | max-width: 384px; 46 | width: 100%; 47 | height: 50%; 48 | display: flex; 49 | flex-direction: column; 50 | align-items: flex-start; 51 | margin: auto; 52 | } 53 | 54 | .title_signIn { 55 | margin-bottom: 20px; 56 | text-align: left; 57 | } 58 | 59 | .form_input { 60 | max-width: 384px; 61 | width: 100%; 62 | font-size: 16px; 63 | font-weight: 400; 64 | line-height: 24px; 65 | height: 40px; 66 | padding: 10px 16px; 67 | border-radius: 8px; 68 | border: none; 69 | appearance: none; 70 | color: var(--black-200); 71 | background-color: var(--gray-200); 72 | } 73 | 74 | .form_label { 75 | margin: 14px 0 4px; 76 | color: var(--black-200); 77 | font-size: 14px; 78 | font-weight: 700; 79 | } 80 | 81 | .signIn_btn { 82 | max-width: 384px; 83 | margin-top: 20px; 84 | width: 100%; 85 | padding: 10px 16px; 86 | cursor: pointer; 87 | border: none; 88 | background: var(--primary); 89 | color: var(--white); 90 | border-radius: 8px; 91 | font-size: 14px; 92 | font-weight: 700; 93 | line-height: 20px; 94 | height: 40px; 95 | appearance: none; 96 | -webkit-appearance: none; 97 | -moz-appearance: none; 98 | } 99 | 100 | .signIn_btn:hover { 101 | opacity: 0.7; 102 | } 103 | 104 | .signIn-img { 105 | width: 100%; 106 | height: 300px; 107 | /* background-color: chocolate; */ 108 | display: flex; 109 | justify-content: center; 110 | align-items: center; 111 | } 112 | 113 | .signIn_img_rocket { 114 | width: 70%; 115 | margin-top: 50px; 116 | background-image: url('/img/rocket.svg'); 117 | height: 100%; 118 | background-repeat: no-repeat; 119 | /* background-color: chocolate; */ 120 | } 121 | 122 | @media screen and (min-width: 750px) { 123 | .signIn { 124 | max-width: 100%; 125 | height: 80vh; 126 | display: flex; 127 | flex-direction: row-reverse; 128 | justify-content: space-between; 129 | align-items: center; 130 | margin-top: 0; 131 | } 132 | .sigIn_form { 133 | width: 60%; 134 | } 135 | 136 | .title_signIn { 137 | text-align: center; 138 | } 139 | 140 | .signIn-img { 141 | width: 50%; 142 | height: 600px; 143 | } 144 | 145 | .signIn_img_rocket { 146 | width: 70%; 147 | background-image: url('/img/cat.svg'); 148 | background-repeat: no-repeat; 149 | background-position: center; 150 | 151 | opacity: 0.7; 152 | } 153 | .signIn_form { 154 | margin: auto; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/components/SignUp.css: -------------------------------------------------------------------------------- 1 | *:focus { 2 | outline: none; 3 | } 4 | 5 | .logo { 6 | width: 100px; 7 | margin-bottom: 10px; 8 | } 9 | 10 | .reset-Info-SignUp { 11 | background-color: var(--white); 12 | fill: var(--primary); 13 | padding: 2px 3px; 14 | border-radius: 100%; 15 | font-weight: bold; 16 | font-size: 20px; 17 | width: 40px; 18 | height: 40px; 19 | box-shadow: 3px 3px 6px var(--gray-600); 20 | /* border: 2px solid var(--primary); */ 21 | margin-top: 20px; 22 | position: fixed; 23 | right: 30px; 24 | cursor: pointer; 25 | appearance: none; 26 | -webkit-appearance: none; 27 | -moz-appearance: none; 28 | text-decoration: none; 29 | } 30 | 31 | .reset-Info-SignUp:hover { 32 | fill: var(--white); 33 | background-color: var(--primary); 34 | box-shadow: 5px 5px 6px var(--gray-600); 35 | } 36 | 37 | .signUp { 38 | max-width: 384px; 39 | width: 80%; 40 | margin: auto; 41 | margin-top: 50px; 42 | } 43 | 44 | .form { 45 | max-width: 384px; 46 | width: 100%; 47 | display: flex; 48 | flex-direction: column; 49 | align-items: flex-start; 50 | } 51 | 52 | .title_signUp { 53 | margin-bottom: 20px; 54 | text-align: left; 55 | } 56 | 57 | .form_input { 58 | width: 100%; 59 | font-size: 16px; 60 | font-weight: 400; 61 | line-height: 24px; 62 | height: 40px; 63 | padding: 10px 16px; 64 | border-radius: 8px; 65 | border: none; 66 | appearance: none; 67 | color: var(--black-200); 68 | background-color: var(--gray-200); 69 | } 70 | 71 | .form_label { 72 | margin: 14px 0 4px; 73 | color: var(--black-200); 74 | font-size: 14px; 75 | font-weight: 700; 76 | } 77 | 78 | .signUp_btn { 79 | max-width: 384px; 80 | margin-top: 20px; 81 | width: 100%; 82 | padding: 10px 16px; 83 | cursor: pointer; 84 | border: none; 85 | background: var(--primary); 86 | color: var(--white); 87 | border-radius: 8px; 88 | font-size: 14px; 89 | font-weight: 700; 90 | line-height: 20px; 91 | height: 40px; 92 | text-align: center; 93 | appearance: none; 94 | -webkit-appearance: none; 95 | -moz-appearance: none; 96 | } 97 | 98 | .signUp_btn:hover { 99 | opacity: 0.7; 100 | } 101 | 102 | .img-fish { 103 | margin-top: 10px; 104 | width: 40%; 105 | } 106 | 107 | .signUp_img { 108 | width: 100%; 109 | height: 300px; 110 | /* background-color: chocolate; */ 111 | display: flex; 112 | justify-content: center; 113 | align-items: center; 114 | } 115 | 116 | .signUp_img_globe { 117 | width: 70%; 118 | margin-top: 50px; 119 | background-image: url('/img/globe.svg'); 120 | height: 100%; 121 | background-repeat: no-repeat; 122 | /* background-color: chocolate; */ 123 | } 124 | 125 | @media screen and (min-width: 750px) { 126 | .signUp { 127 | max-width: 100%; 128 | height: 80vh; 129 | display: flex; 130 | flex-direction: row-reverse; 131 | justify-content: space-between; 132 | align-items: center; 133 | margin-top: 0; 134 | } 135 | .form { 136 | width: 60%; 137 | } 138 | 139 | .title_signUp { 140 | text-align: center; 141 | } 142 | 143 | .signUp_img { 144 | width: 50%; 145 | height: 600px; 146 | } 147 | 148 | .signUp_img_globe { 149 | width: 70%; 150 | background-image: url('/img/sign-up-globe.svg'); 151 | background-repeat: no-repeat; 152 | background-position: center; 153 | 154 | opacity: 0.7; 155 | } 156 | .form { 157 | margin: auto; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/components/icons/IconCalendar.js: -------------------------------------------------------------------------------- 1 | function IconCalendar({ className }) { 2 | return ( 3 | 8 | 12 | 16 | 17 | ); 18 | } 19 | 20 | export default IconCalendar; 21 | -------------------------------------------------------------------------------- /src/components/icons/IconClock.js: -------------------------------------------------------------------------------- 1 | function IconClock({ className }) { 2 | return ( 3 | 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | 25 | export default IconClock; 26 | -------------------------------------------------------------------------------- /src/components/icons/IconDelete.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const IconDelete = ({ className }) => { 4 | return ( 5 | 10 | 14 | 18 | 19 | ); 20 | }; 21 | 22 | export default IconDelete; 23 | -------------------------------------------------------------------------------- /src/components/icons/IconEdit.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const IconEdit = ({ className }) => { 4 | return ( 5 | 10 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default IconEdit; 20 | -------------------------------------------------------------------------------- /src/components/icons/IconLink.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const IconLink = ({ className }) => { 4 | return ( 5 | 10 | 14 | 18 | 19 | ); 20 | }; 21 | 22 | export default IconLink; 23 | -------------------------------------------------------------------------------- /src/components/icons/IconLocation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const IconLocation = ({ className }) => { 4 | return ( 5 | 10 | 11 | 15 | 19 | 20 | 21 | ); 22 | }; 23 | 24 | export default IconLocation; 25 | -------------------------------------------------------------------------------- /src/components/icons/IconReset.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const IconReset = ({ className }) => { 4 | return ( 5 | 10 | 15 | 16 | ); 17 | }; 18 | 19 | export default IconReset; 20 | -------------------------------------------------------------------------------- /src/components/icons/IconTarget.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const IconTarget = ({ className }) => { 4 | return ( 5 | 10 | 14 | 18 | 19 | ); 20 | }; 21 | 22 | export default IconTarget; 23 | -------------------------------------------------------------------------------- /src/components/icons/IconZoomIn.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const IconZoomIn = ({ className }) => { 4 | return ( 5 | 10 | 11 | 15 | 16 | ); 17 | }; 18 | 19 | export default IconZoomIn; 20 | -------------------------------------------------------------------------------- /src/context/userContext.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, createContext } from 'react'; 2 | 3 | const Context = createContext(); 4 | 5 | export function UserContextProvider({ children }) { 6 | const [user, setUser] = useState([]) 7 | useEffect(() => { 8 | const user = JSON.parse(localStorage.getItem("timekids-user")); 9 | 10 | if (user) { 11 | // setUserData(user); 12 | setUser(user); 13 | 14 | } 15 | }, []); 16 | return 17 | {children} 18 | 19 | } 20 | 21 | export default Context; -------------------------------------------------------------------------------- /src/globalStyles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | * { 11 | margin: 0; 12 | padding: 0; 13 | box-sizing: border-box; 14 | } 15 | 16 | :root { 17 | --white: #ffffff; 18 | --black: #000000; 19 | --black-200: #0d0c22; 20 | --gray-200: #f1f1f2; 21 | --gray-500: #dcddde; 22 | --gray-600: #c6c8ca; 23 | --gray-800: #858686; 24 | --primary: #ea4c89; 25 | /* --secondary: #822659; 26 | --primary-light: #f8a1d1; */ 27 | } 28 | a { 29 | text-decoration: none; 30 | color: var(--gray-8000); 31 | } 32 | /* code { 33 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 34 | monospace; 35 | } */ 36 | 37 | /* font: bold 15px/24px 'Haas Grot Text R Web', 'Helvetica Neue', Helvetica, 38 | Arial, sans-serif; */ 39 | 40 | /* font-family: 'Haas Grot Text R Web', 'Helvetica Neue', Helvetica, Arial, 41 | sans-serif; */ 42 | -------------------------------------------------------------------------------- /src/hooks/useField.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | export default function useField(inputProps) { 4 | const [value, setValue] = useState(""); 5 | const onChange = ({ target }) => { 6 | setValue(target.value); 7 | }; 8 | return { 9 | ...inputProps, 10 | value, 11 | onChange, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/hooks/useUser.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useContext } from "react"; 2 | import storage from "utils/localStorage.js"; 3 | import { signUp, signIn } from "utils/api"; 4 | import userContext from "context/userContext"; 5 | 6 | export default function useUser() { 7 | // const [userData, setUserData] = useState({ userId: null }); 8 | const { user, setUser } = useContext(userContext); 9 | 10 | useEffect(() => { 11 | const user = JSON.parse(localStorage.getItem("timekids-user")); 12 | 13 | if (user) { 14 | // setUserData(user); 15 | setUser(user); 16 | 17 | } 18 | }, []); 19 | 20 | const register = (userName, password) => { 21 | 22 | return signUp(userName, password).then((resp) => { 23 | if (resp.user) { 24 | const { email, id } = resp.user; 25 | const userData = { userId: id, email }; 26 | // setUserData(userData); 27 | setUser(userData); 28 | storage.setUser(userData); 29 | return { status: 200 } 30 | } else return resp.error; 31 | }); 32 | }; 33 | const login = (userName, password) => { 34 | return signIn(userName, password).then((resp) => { 35 | 36 | if (resp.data != null) { 37 | const { email, id } = resp.user; 38 | const userData = { userId: id, email }; 39 | // setUserData(userData); 40 | setUser(userData); 41 | storage.setUser(userData); 42 | return { status: 200 } 43 | } else { 44 | return resp.error; 45 | // Error mostrarlo con toast 46 | } 47 | }); 48 | }; 49 | 50 | return { 51 | register, 52 | login, 53 | user, 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/pages/_app.js: -------------------------------------------------------------------------------- 1 | import "globalStyles.css"; 2 | import "App.css"; 3 | import "components/CreateEvents.css"; 4 | import "components/EmptyEvents.css"; 5 | import "components/Events.css"; 6 | import "components/Footer.css"; 7 | import "components/Header.css"; 8 | import "components/HeaderDate.css"; 9 | import "components/Info.css"; 10 | import "components/InfoDetailEvent.css"; 11 | import "components/ListEvents.css"; 12 | import "components/Loading.css"; 13 | import "components/SignIn.css"; 14 | import "components/SignUp.css"; 15 | 16 | import Head from "next/head"; 17 | 18 | import Header from "components/Header.js"; 19 | import { UserContextProvider } from "context/userContext"; 20 | 21 | function App({ Component, pageProps }) { 22 | return ( 23 | <> 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 |
33 | 34 | ); 35 | } 36 | 37 | export default App; 38 | -------------------------------------------------------------------------------- /src/pages/createEvents/[id].js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useContext } from "react"; 2 | import { useRouter } from "next/router"; 3 | import Link from "next/link"; 4 | import { createEvent, getEventDetails } from "utils/api"; 5 | import IconReset from "components/icons/IconReset.js"; 6 | import Head from "next/head"; 7 | import useField from "hooks/useField.js"; 8 | import userContext from "context/userContext"; 9 | 10 | export default function CreateEvents() { 11 | const { id } = useRouter().query; 12 | const history = useRouter(); 13 | 14 | const { user } = useContext(userContext) 15 | const { userId } = user 16 | const [error, setErrorMessage] = useState(""); 17 | const eventImgField = useField({ type: "text", name: "eventImg" }); 18 | const eventNameField = useField({ type: "text", name: "eventName" }); 19 | const eventLinkField = useField({ type: "text", name: "eventLink" }); 20 | const eventAgeField = useField({ type: "text", name: "eventAge" }); 21 | const eventCityField = useField({ type: "text", name: "eventCity" }); 22 | const eventInformationField = useField({ 23 | type: "text", 24 | name: "eventInformation", 25 | }); 26 | const eventHourField = useField({ type: "text", name: "eventHour" }); 27 | const eventDateField = useField({ type: "date", name: "eventDate" }); 28 | const eventUrlField = useField({ type: "text", name: "eventUrl" }); 29 | // const eventFileField = useField({ type: "file", name: "eventFile" }); 30 | const [eventData, setEventData] = useState({ 31 | title: "", 32 | imageUrl: "", 33 | date: "", 34 | url: "", 35 | age: 0, 36 | city: "", 37 | info: "", 38 | hour: "", 39 | user_id: userId, 40 | }); 41 | 42 | useEffect(() => { 43 | if (id !== "new" && id !== undefined) { 44 | getEventDetails(id).then(({ data }) => { 45 | 46 | setEventData({ 47 | title: data[0].title, 48 | imageUrl: data[0].image, 49 | date: data[0].date, 50 | url: data[0].url, 51 | age: data[0].age, 52 | city: data[0].city, 53 | info: data[0].info, 54 | hour: data[0].hour, 55 | user_id: userId, 56 | }); 57 | }); 58 | } else if (id === "new") { 59 | setEventData({ 60 | title: "", 61 | imageUrl: "", 62 | date: "", 63 | url: "", 64 | age: 0, 65 | city: "", 66 | info: "", 67 | hour: "", 68 | user_id: userId, 69 | }); 70 | } 71 | }, [id]); 72 | 73 | const handleFormEvent = (ev) => { 74 | ev.preventDefault(); 75 | const data = { 76 | title: eventNameField.value, 77 | imageUrl: eventImgField.value, 78 | date: eventDateField.value, 79 | url: eventLinkField.value, 80 | age: eventAgeField.value, 81 | city: eventCityField.value, 82 | info: eventInformationField.value, 83 | hour: eventHourField.value, 84 | user_id: userId, 85 | } 86 | setEventData(data); 87 | 88 | createEvent(data) 89 | .then((resp) => { 90 | 91 | if (resp.error) { 92 | setErrorMessage(resp.error.message); 93 | setTimeout(() => setErrorMessage(""), 3000); 94 | } else if (resp.status === 201) { 95 | history.push("/"); 96 | } 97 | }) 98 | .catch((error) => setErrorMessage(error.message)); 99 | }; 100 | const updateEvent = () => { 101 | 102 | // setEventData({ 103 | // title:eventData.title, 104 | // image:eventData.image, 105 | // date:eventData.date, 106 | // url:eventData.url, 107 | // age:eventData.age, 108 | // city:eventData.city, 109 | // info:eventData.info, 110 | // hour:eventData.hour, 111 | // user_id: userId, 112 | // }); 113 | }; 114 | const isSubmitDisabled = 115 | !eventNameField.value || !eventHourField.value || !eventDateField.value; 116 | 117 | return ( 118 | <> 119 | 120 | Agenda Peques - Crear evento 121 | 126 | 132 | 133 | 134 | 135 | 136 | 137 | 138 |
139 |
140 |
141 |
142 |
143 |

Crear Evento

144 |
145 | 148 | 154 | 157 | 163 | 166 | 172 | {/* */} 178 | 181 | 190 | 193 | 200 | 201 | 202 | 205 | 210 | 213 | 214 | 217 | 224 | {error !== "" ?

{error}

: <>} 225 | 231 |
232 |
233 |
234 | 235 | ); 236 | } 237 | -------------------------------------------------------------------------------- /src/pages/eventDetail/[id].js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, } from "react"; 2 | import Link from "next/link"; 3 | import { useRouter } from "next/router"; 4 | import IconCalendar from "components/icons/IconCalendar.js"; 5 | import IconClock from "components/icons/IconClock.js"; 6 | import IconLocation from "components/icons/IconLocation.js"; 7 | import IconLink from "components/icons/IconLink.js"; 8 | import IconZoomIn from "components/icons/IconZoomIn.js"; 9 | import IconTarget from "components/icons/IconTarget.js"; 10 | import IconReset from "components/icons/IconReset.js"; 11 | import { formatDate } from "utils/tools"; 12 | import { getEventDetails } from "utils/api"; 13 | 14 | const InfoDetailEvent = () => { 15 | const { id } = useRouter().query; 16 | const [event, setEvent] = useState({}); 17 | const history = useRouter(); 18 | 19 | useEffect(() => { 20 | if (id) getEventDetails(id).then(({ data }) => setEvent(data[0])); 21 | else history.replace("/"); 22 | }, [id]); 23 | 24 | const age = event.age ? event.age : "- -"; 25 | const city = event.city ? event.city : "- -"; 26 | const information = event.info ? event.info : "- -"; 27 | const url = event.url ? event.url : "- -"; 28 | const hour = event.hour || "- -"; 29 | // const hour = event.hour ? event.hour.slice(0, -3) : "- -"; 30 | const date = formatDate(event.date); 31 | // const date = date1 ? date1 : "- -"; 32 | 33 | return ( 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 | Poster del evento 48 |
49 |
50 |

{event.title}

51 |
52 | 53 |

{date}

54 |
55 |
56 | 57 |

{hour} horas

58 |
59 |
60 | 61 |
62 | 63 |

{city}

64 |
65 | 66 |
67 | 68 |

{age} años

69 |
70 | 71 |
72 | 73 |

{information}

74 |
75 | 76 |
77 | 78 | 79 | {url} 80 | 81 |
82 |
83 |
84 |
85 |
86 | ); 87 | }; 88 | 89 | export default InfoDetailEvent; 90 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useContext } from "react"; 2 | import Head from "next/head"; 3 | 4 | import { getEventsFromDate } from "utils/api"; 5 | import { getTodayDate, groupByDate, sortObject } from "utils/tools"; 6 | import EmptyEvents from "components/EmptyEvents.js"; 7 | import Events from "components/Events.js"; 8 | import Loading from "components/Loading.js"; 9 | import userContext from "context/userContext"; 10 | 11 | const LOADING_STATES = { 12 | empty: "empty", 13 | loading: "loading", 14 | }; 15 | 16 | const ListEvents = () => { 17 | const { user, setUser } = useContext(userContext); 18 | 19 | const [events, setEvents] = useState([]); 20 | const [status, setStatus] = useState(LOADING_STATES.loading); 21 | const [errorMessage, setErrorMessage] = useState(""); 22 | 23 | useEffect(() => { 24 | const today = getTodayDate(); 25 | getEventsFromDate(today).then((resp) => { 26 | if (resp.status === 200) { 27 | const { data } = resp; 28 | const grouped = groupByDate(data); 29 | const sorted = sortObject(grouped); 30 | setEvents(sorted); 31 | 32 | const newStatus = data.length <= 0 ? "empty" : "loaded"; 33 | setStatus(newStatus); 34 | } else { 35 | setErrorMessage("Ha habido algún error. Vuelve a cargar la página. "); 36 | } 37 | }); 38 | }, []); 39 | 40 | function renderEvents() { 41 | const dates = Object.keys(events); 42 | return dates.map((date) => { 43 | return ( 44 |
45 | 46 |
47 | ); 48 | }); 49 | } 50 | 51 | if (status === LOADING_STATES.loading) { 52 | return ; 53 | } 54 | 55 | if (status === LOADING_STATES.empty) { 56 | return ; 57 | } 58 | 59 | return ( 60 | <> 61 | 62 | Agenda Peques Eivissa 63 | 64 | 70 | 71 |
72 |
73 |
74 |
75 | {errorMessage !== "" ? ( 76 |

{errorMessage}

77 | ) : ( 78 | <> 79 | )} 80 |
{renderEvents()}
81 |
82 | 83 | ); 84 | }; 85 | 86 | export default ListEvents; 87 | -------------------------------------------------------------------------------- /src/pages/info.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import Link from "next/link"; 3 | 4 | export default function Info() { 5 | return ( 6 | <> 7 | 8 | Agenda Peques - Info del proyecto 9 | 14 | 20 | 21 |
22 | 23 | Volver a Eventos 24 | 25 | 26 |

27 | CAT- Hola. Volia, simplement, explicar-te què és i el perquè d'aquest 28 | projecte. Aquesta web surt de la meva pròpia necessitat 29 | d'assabentar-me dels esdeveniments que hi ha a l'illa per a anar amb 30 | la meva família, especialment amb els meus fills petits. Durant uns 31 | anys he buscat en agendes en línia de l'illa i no he trobat cap que 32 | compti amb esdeveniments infantils especialment o són massa 33 | especialitzades en esdeveniments concrets (escoles o biblioteques) o 34 | en població concreta (Ajuntaments). La majoria de vegades és per boca 35 | a boca i per això aquest projecte està pensat perquè les famílies ens 36 | ajudem entre nosaltres a trobar esdeveniments infantils. La idea és 37 | que quan sapiguem d'un esdeveniment infantil a l'illa el publiquem 38 | qualsevol de nosaltres. Aquesta és la raó d'haver de donar-te d'alta, 39 | perquè la teva puguis publicar esdeveniments, i com que és una web de 40 | contingut infantil, hi hagi un mínim control queda guardat un 41 | identificador d'usuari per si algun contingut no fos adequat, 42 | cancel·lar aquest compte. No crec se de el cas però crec que haig de 43 | protegir els nens que puguin entrar en aquesta web. No crec que aquest 44 | projecte creixi tant com per a necessitar una validació anterior però 45 | si fes falta, es faria... Si ets professional del sector, pots 46 | donar-te d'alta i publicar les teves bitlles, estarem encantad@s! Si 47 | ets Ajuntament, biblioteca o col·legi, també ets més que benvingut. 48 |

49 |

50 |

51 | CAST-Quería, simplemente, explicarte qué es y el porqué de este 52 | proyecto. Esta web sale de mi propia necesidad de enterarme de los 53 | eventos que hay en la isla para ir con mi familia, especialmente con 54 | mis hijos pequeños. Durante unos años he buscado en agendas online de 55 | la isla y no he encontrado ninguna que cuente con eventos infantiles 56 | especialmente o son demasiado especializadas en eventos concretos 57 | (escuelas o bibliotecas) o en población concreta (ayuntamientos). La 58 | mayoría de veces es por boca a boca y por eso este proyecto está 59 | pensado para que las familias nos ayudemos entre nosotros a encontrar 60 | eventos infantiles. La idea es que cuando sepamos de un evento 61 | infantil lo publiquemos.Esta es la razón de tener que darte de alta, 62 | para que tu puedas publicar eventos, y puesto que es una web de 63 | contenido infantil, haya un mínimo control queda guardado un 64 | identificador de usuario por si algún contenido no fuera adecuado, 65 | cancelar esa cuenta. No creo se de el caso pero creo que debo proteger 66 | a los peques que puedan entrar en esta web. No creo que este proyecto 67 | crezca tanto como para necesitar una validación anterior pero si 68 | hiciera falta, se haría... Si eres profesional del sector, puedes 69 | darte de alta y publicar tus bolos, estaremos encantad@s! Si eres 70 | Ayuntamiento, biblioteca o colegio, también eres más que bienvenido. 71 |

72 |
73 | 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /src/pages/signIn.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useRouter } from "next/router"; 3 | import Link from "next/link"; 4 | import IconReset from "components/icons/IconReset.js"; 5 | import Head from "next/head"; 6 | import useUser from "hooks/useUser.js"; 7 | import useField from "hooks/useField.js"; 8 | 9 | const SignIn = () => { 10 | const userNameField = useField({ type: "text", name: "username" }); 11 | const passwordField = useField({ type: "password", name: "password" }); 12 | const [errorMessage, setErrorMessage] = useState(""); 13 | 14 | const { 15 | login, 16 | // userData: { userId }, 17 | } = useUser(); 18 | const history = useRouter(); 19 | 20 | function handleFormSignIn(ev) { 21 | ev.preventDefault(); 22 | 23 | login(userNameField.value, passwordField.value) 24 | .then((resp) => { 25 | 26 | if (resp.status === 200) { 27 | history.push("/"); 28 | } else { 29 | setErrorMessage(resp.message); 30 | setTimeout(() => setErrorMessage(""), 3000); 31 | } 32 | }) 33 | } 34 | 35 | return ( 36 | <> 37 | 38 | Agenda Peques - Iniciar sesión 39 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
57 |
58 |

Sign in

59 |
60 | 63 | 68 | 71 | 76 | 77 |
78 |
79 | {errorMessage !== "" ? ( 80 |

{errorMessage}

81 | ) : ( 82 | <> 83 | )} 84 | 85 |
86 |
87 |
88 |
89 | 90 | ); 91 | }; 92 | 93 | export default SignIn; 94 | -------------------------------------------------------------------------------- /src/pages/signUp.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useRouter } from "next/router"; 3 | import Link from "next/link"; 4 | import IconReset from "components/icons/IconReset.js"; 5 | 6 | import Head from "next/head"; 7 | import useUser from "hooks/useUser.js"; 8 | import useField from "hooks/useField.js"; 9 | 10 | const SignUp = () => { 11 | const { register } = useUser(); 12 | const userNameField = useField({ type: "text", name: "username" }); 13 | const userPasswField = useField({ type: "password", name: "userpassw" }); 14 | const confirmPasswField = useField({ 15 | type: "password", 16 | name: "confirmpassw", 17 | }); 18 | 19 | const [error, setErrorMessage] = useState(""); 20 | 21 | const history = useRouter(); 22 | 23 | function handleFormSignUp(ev) { 24 | ev.preventDefault(); 25 | 26 | if (userPasswField.value === confirmPasswField.value) { 27 | 28 | register(userNameField.value, userPasswField.value).then((resp) => { 29 | if (resp.status === 200) { 30 | history.push("/"); 31 | } else { 32 | setErrorMessage(resp.message); 33 | setTimeout(() => setErrorMessage(""), 3000); 34 | } 35 | }); 36 | } else { 37 | setErrorMessage("Passwords Diferentes"); 38 | setTimeout(() => setErrorMessage(""), 3000); 39 | } 40 | } 41 | 42 | // const disableButton = 43 | // !userNameField || 44 | // userNameField.length < 3 || 45 | // !userPasswField || 46 | // !confirmPassword; 47 | 48 | return ( 49 | <> 50 | 51 | Agenda Peques - Crear nueva cuenta 52 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 |
71 |

Sign Up

72 |
73 | 76 | 81 | 84 | 89 | 92 | 97 | 103 |
104 | {error !== "" ?

{error}

: <>} 105 |
106 |
107 |
108 |
109 |
110 | 111 | ); 112 | }; 113 | 114 | export default SignUp; 115 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/utils/api.js: -------------------------------------------------------------------------------- 1 | import { createClient } from "@supabase/supabase-js"; 2 | 3 | const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; 4 | const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_KEY; 5 | 6 | const supabase = createClient(supabaseUrl, supabaseKey); 7 | 8 | const api = {}; 9 | 10 | export function createEvent(eventData) { 11 | return supabase.from("events").insert([eventData]); 12 | } 13 | 14 | api.updateEvent = async function (eventId, eventData) { 15 | const { data } = await supabase 16 | .from("events") 17 | .update(eventData) 18 | .eq("id", eventId); 19 | 20 | return data; 21 | }; 22 | 23 | api.deleteEvent = async function (eventId) { 24 | await supabase.from("events").delete().eq("id", eventId); 25 | }; 26 | 27 | export function getEventDetails(eventId) { 28 | return supabase.from("events").select("*").eq("id", eventId); 29 | } 30 | 31 | export function getEventsFromDate(date) { 32 | return ( 33 | supabase 34 | .from("events") 35 | .select("*") 36 | // filtrar eventos a partir de la fecha que le pongamos 37 | .gte("date", date) 38 | ); 39 | } 40 | 41 | export function signIn(email, password) { 42 | 43 | return supabase.auth.signIn({ 44 | email, 45 | password, 46 | }); 47 | } 48 | 49 | export function signUp(email, password) { 50 | 51 | return supabase.auth.signUp({ 52 | email, 53 | password, 54 | }); 55 | } 56 | 57 | export default api; 58 | -------------------------------------------------------------------------------- /src/utils/localStorage.js: -------------------------------------------------------------------------------- 1 | const LOCAL_STORAGE_USER_KEY = "timekids-user"; 2 | 3 | const storage = { 4 | getUser: () => JSON.parse(localStorage.getItem(LOCAL_STORAGE_USER_KEY)), 5 | setUser: (userData) => { 6 | localStorage.setItem(LOCAL_STORAGE_USER_KEY, JSON.stringify(userData)); 7 | }, 8 | wipeUser: () => { 9 | localStorage.removeItem(LOCAL_STORAGE_USER_KEY); 10 | }, 11 | }; 12 | 13 | export default storage; 14 | -------------------------------------------------------------------------------- /src/utils/tools.js: -------------------------------------------------------------------------------- 1 | export function groupByDate(arr) { 2 | let groups = {}; 3 | if (arr) { 4 | for (let i = 0; i < arr.length; i++) { 5 | const date = arr[i].date; 6 | 7 | if (!groups[date]) { 8 | groups[date] = [arr[i]]; 9 | } else { 10 | groups[date].push(arr[i]); 11 | } 12 | } 13 | } 14 | return groups; 15 | } 16 | 17 | // https://stackoverflow.com/a/29622653 18 | export const sortObject = (o) => 19 | Object.keys(o) 20 | .sort() 21 | // eslint-disable-next-line no-sequences 22 | .reduce((r, k) => ((r[k] = o[k]), r), {}); 23 | 24 | export function getTodayDate() { 25 | const today = new Date(); 26 | const month = today.getMonth() + 1; 27 | const day = today.getDate(); 28 | 29 | const formattedMonth = month < 10 ? "0" + month : month; 30 | const formattedDay = day < 10 ? "0" + day : day; 31 | 32 | const date = `${today.getFullYear()}-${formattedMonth}-${formattedDay}`; 33 | 34 | return date; 35 | } 36 | 37 | export function formatDate(str) { 38 | const date = new Date(str); 39 | const month = date.getMonth() + 1; 40 | const day = date.getDate(); 41 | 42 | const formattedMonth = month < 10 ? "0" + month : month; 43 | const formattedDay = day < 10 ? "0" + day : day; 44 | 45 | return `${formattedDay}-${formattedMonth}-${date.getFullYear()}`; 46 | } 47 | -------------------------------------------------------------------------------- /src/utils/tools.test.js: -------------------------------------------------------------------------------- 1 | import { groupByDate } from './tools'; 2 | 3 | const ungrouped = [ 4 | { 5 | name: 'Evento 2', 6 | date: '2021-04-29', 7 | }, 8 | { 9 | name: 'Evento 4', 10 | date: '2022-03-02', 11 | }, 12 | { 13 | name: 'Evento 1', 14 | date: '2021-03-02', 15 | }, 16 | { 17 | name: 'Evento 3', 18 | date: '2021-04-29', 19 | }, 20 | ]; 21 | 22 | const grouped = { 23 | '2021-04-29': [ 24 | { 25 | name: 'Evento 2', 26 | date: '2021-04-29', 27 | }, 28 | { 29 | name: 'Evento 3', 30 | date: '2021-04-29', 31 | }, 32 | ], 33 | '2022-03-02': [ 34 | { 35 | name: 'Evento 4', 36 | date: '2022-03-02', 37 | }, 38 | ], 39 | '2021-03-02': [ 40 | { 41 | name: 'Evento 1', 42 | date: '2021-03-02', 43 | }, 44 | ], 45 | }; 46 | 47 | describe('groupByDate', () => { 48 | test('it groups objects by date', () => { 49 | const want = grouped; 50 | const got = groupByDate(ungrouped); 51 | 52 | expect(got).toEqual(want); 53 | }); 54 | }); 55 | --------------------------------------------------------------------------------