From 7400a5b50d7966c60c4aced12f89c26875f57882 Mon Sep 17 00:00:00 2001 From: Bradley Shellnut Date: Thu, 3 Jun 2021 17:58:40 -0700 Subject: [PATCH] Adding wedding website files. --- .vscode/launch.json | 12 + README.md | 17 + components/CustomNextCloudinaryImage.js | 81 + components/CustomNextImage.js | 63 + components/Event.js | 69 + components/Footer.js | 75 + components/Form.js | 43 + components/GuestRSVP.js | 118 + components/Header.js | 51 + components/HomeContent.js | 23 + components/Layout.js | 23 + components/Login.js | 176 + components/Modal.js | 95 + components/Nav.js | 30 + components/NavLink.js | 19 + components/Page.js | 339 + components/PlusOneRSVP.js | 122 + components/Timeline.js | 11 + components/Typography.js | 77 + components/WeddingStart.js | 22 + components/styles/Form.js | 75 + components/styles/LayoutStyles.js | 16 + components/styles/NavStyles.js | 38 + components/styles/nprogress.css | 80 + lib/events.json | 69 + lib/fetchJson.js | 24 + lib/session.js | 14 + lib/svgs.js | 35 + lib/useForm.js | 71 + lib/useModal.js | 16 + lib/useUser.js | 27 + lib/utils.js | 7 + models/Group.js | 20 + models/Guest.js | 26 + models/User.js | 15 + next.config.js | 5 + package-lock.json | 14745 ++++++++++++++++ package.json | 111 + pages/404.js | 14 + pages/_app.js | 51 + pages/_document.js | 25 + pages/api/group.js | 93 + pages/api/guest.js | 38 + pages/api/login.js | 36 + pages/api/logout.js | 6 + pages/api/permissions.js | 38 + pages/api/register.js | 27 + pages/api/rsvp.js | 34 + pages/api/user.js | 18 + pages/cats.js | 80 + pages/home.js | 28 + pages/index.js | 36 + pages/login.js | 5 + pages/logout.js | 35 + pages/party.js | 145 + pages/photos.js | 113 + pages/profile-sg.js | 37 + pages/profile-ssr.js | 61 + pages/qanda.js | 57 + pages/register.js | 100 + pages/rsvp/[id].js | 418 + pages/rsvp/index.js | 123 + pages/travelstay.js | 123 + public/assets/Background.jpeg | Bin 0 -> 178395 bytes public/favicon.ico | Bin 0 -> 10462 bytes public/fonts/Istok_Web/IstokWeb-Bold.ttf | Bin 0 -> 221656 bytes .../fonts/Istok_Web/IstokWeb-BoldItalic.ttf | Bin 0 -> 215400 bytes public/fonts/Istok_Web/IstokWeb-Italic.ttf | Bin 0 -> 215376 bytes public/fonts/Istok_Web/IstokWeb-Regular.ttf | Bin 0 -> 312120 bytes public/fonts/Istok_Web/OFL.txt | 94 + .../JosefinSans-Italic-VariableFont_wght.ttf | Bin 0 -> 124224 bytes .../JosefinSans-VariableFont_wght.ttf | Bin 0 -> 115664 bytes public/fonts/Josefin_Sans/OFL.txt | 93 + public/fonts/Josefin_Sans/README.txt | 77 + .../Josefin_Sans/static/JosefinSans-Bold.ttf | Bin 0 -> 58416 bytes .../static/JosefinSans-BoldItalic.ttf | Bin 0 -> 62568 bytes .../static/JosefinSans-ExtraLight.ttf | Bin 0 -> 58568 bytes .../static/JosefinSans-ExtraLightItalic.ttf | Bin 0 -> 62708 bytes .../static/JosefinSans-Italic.ttf | Bin 0 -> 62660 bytes .../Josefin_Sans/static/JosefinSans-Light.ttf | Bin 0 -> 58584 bytes .../static/JosefinSans-LightItalic.ttf | Bin 0 -> 62676 bytes .../static/JosefinSans-Medium.ttf | Bin 0 -> 58560 bytes .../static/JosefinSans-MediumItalic.ttf | Bin 0 -> 62792 bytes .../static/JosefinSans-Regular.ttf | Bin 0 -> 58548 bytes .../static/JosefinSans-SemiBold.ttf | Bin 0 -> 58580 bytes .../static/JosefinSans-SemiBoldItalic.ttf | Bin 0 -> 62820 bytes .../Josefin_Sans/static/JosefinSans-Thin.ttf | Bin 0 -> 58400 bytes .../static/JosefinSans-ThinItalic.ttf | Bin 0 -> 62460 bytes public/fonts/Kanit/Kanit-Black.ttf | Bin 0 -> 173492 bytes public/fonts/Kanit/Kanit-BlackItalic.ttf | Bin 0 -> 182076 bytes public/fonts/Kanit/Kanit-Bold.ttf | Bin 0 -> 172876 bytes public/fonts/Kanit/Kanit-BoldItalic.ttf | Bin 0 -> 180308 bytes public/fonts/Kanit/Kanit-ExtraBold.ttf | Bin 0 -> 174464 bytes public/fonts/Kanit/Kanit-ExtraBoldItalic.ttf | Bin 0 -> 184928 bytes public/fonts/Kanit/Kanit-ExtraLight.ttf | Bin 0 -> 160796 bytes public/fonts/Kanit/Kanit-ExtraLightItalic.ttf | Bin 0 -> 164908 bytes public/fonts/Kanit/Kanit-Italic.ttf | Bin 0 -> 171876 bytes public/fonts/Kanit/Kanit-Light.ttf | Bin 0 -> 168036 bytes public/fonts/Kanit/Kanit-LightItalic.ttf | Bin 0 -> 171596 bytes public/fonts/Kanit/Kanit-Medium.ttf | Bin 0 -> 171336 bytes public/fonts/Kanit/Kanit-MediumItalic.ttf | Bin 0 -> 172360 bytes public/fonts/Kanit/Kanit-Regular.ttf | Bin 0 -> 169744 bytes public/fonts/Kanit/Kanit-SemiBold.ttf | Bin 0 -> 171548 bytes public/fonts/Kanit/Kanit-SemiBoldItalic.ttf | Bin 0 -> 172244 bytes public/fonts/Kanit/Kanit-Thin.ttf | Bin 0 -> 155788 bytes public/fonts/Kanit/Kanit-ThinItalic.ttf | Bin 0 -> 161688 bytes public/fonts/Kanit/OFL.txt | 93 + public/fonts/Parisienne/OFL.txt | 94 + .../fonts/Parisienne/Parisienne-Regular.ttf | Bin 0 -> 58268 bytes public/myevents.ics | 41 + public/pattern.svg | 1 + public/penguin.svg | 14 + seed-data/data.js | 21 + seed-data/index.js | 35 + styles/Home.module.css | 122 + styles/globals.css | 16 + utils/db.js | 32 + utils/useInterval.js | 21 + 118 files changed, 19355 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 README.md create mode 100644 components/CustomNextCloudinaryImage.js create mode 100644 components/CustomNextImage.js create mode 100644 components/Event.js create mode 100644 components/Footer.js create mode 100644 components/Form.js create mode 100644 components/GuestRSVP.js create mode 100644 components/Header.js create mode 100644 components/HomeContent.js create mode 100644 components/Layout.js create mode 100644 components/Login.js create mode 100644 components/Modal.js create mode 100644 components/Nav.js create mode 100644 components/NavLink.js create mode 100644 components/Page.js create mode 100644 components/PlusOneRSVP.js create mode 100644 components/Timeline.js create mode 100644 components/Typography.js create mode 100644 components/WeddingStart.js create mode 100644 components/styles/Form.js create mode 100644 components/styles/LayoutStyles.js create mode 100644 components/styles/NavStyles.js create mode 100755 components/styles/nprogress.css create mode 100644 lib/events.json create mode 100644 lib/fetchJson.js create mode 100644 lib/session.js create mode 100644 lib/svgs.js create mode 100644 lib/useForm.js create mode 100644 lib/useModal.js create mode 100644 lib/useUser.js create mode 100644 lib/utils.js create mode 100644 models/Group.js create mode 100644 models/Guest.js create mode 100644 models/User.js create mode 100644 next.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pages/404.js create mode 100644 pages/_app.js create mode 100644 pages/_document.js create mode 100644 pages/api/group.js create mode 100644 pages/api/guest.js create mode 100644 pages/api/login.js create mode 100644 pages/api/logout.js create mode 100644 pages/api/permissions.js create mode 100644 pages/api/register.js create mode 100644 pages/api/rsvp.js create mode 100644 pages/api/user.js create mode 100644 pages/cats.js create mode 100644 pages/home.js create mode 100644 pages/index.js create mode 100644 pages/login.js create mode 100644 pages/logout.js create mode 100644 pages/party.js create mode 100644 pages/photos.js create mode 100644 pages/profile-sg.js create mode 100644 pages/profile-ssr.js create mode 100644 pages/qanda.js create mode 100644 pages/register.js create mode 100644 pages/rsvp/[id].js create mode 100644 pages/rsvp/index.js create mode 100644 pages/travelstay.js create mode 100644 public/assets/Background.jpeg create mode 100644 public/favicon.ico create mode 100644 public/fonts/Istok_Web/IstokWeb-Bold.ttf create mode 100644 public/fonts/Istok_Web/IstokWeb-BoldItalic.ttf create mode 100644 public/fonts/Istok_Web/IstokWeb-Italic.ttf create mode 100644 public/fonts/Istok_Web/IstokWeb-Regular.ttf create mode 100644 public/fonts/Istok_Web/OFL.txt create mode 100644 public/fonts/Josefin_Sans/JosefinSans-Italic-VariableFont_wght.ttf create mode 100644 public/fonts/Josefin_Sans/JosefinSans-VariableFont_wght.ttf create mode 100644 public/fonts/Josefin_Sans/OFL.txt create mode 100644 public/fonts/Josefin_Sans/README.txt create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-Bold.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-BoldItalic.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-ExtraLight.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-ExtraLightItalic.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-Italic.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-Light.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-LightItalic.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-Medium.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-MediumItalic.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-Regular.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-SemiBold.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-SemiBoldItalic.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-Thin.ttf create mode 100644 public/fonts/Josefin_Sans/static/JosefinSans-ThinItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-Black.ttf create mode 100644 public/fonts/Kanit/Kanit-BlackItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-Bold.ttf create mode 100644 public/fonts/Kanit/Kanit-BoldItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-ExtraBold.ttf create mode 100644 public/fonts/Kanit/Kanit-ExtraBoldItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-ExtraLight.ttf create mode 100644 public/fonts/Kanit/Kanit-ExtraLightItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-Italic.ttf create mode 100644 public/fonts/Kanit/Kanit-Light.ttf create mode 100644 public/fonts/Kanit/Kanit-LightItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-Medium.ttf create mode 100644 public/fonts/Kanit/Kanit-MediumItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-Regular.ttf create mode 100644 public/fonts/Kanit/Kanit-SemiBold.ttf create mode 100644 public/fonts/Kanit/Kanit-SemiBoldItalic.ttf create mode 100644 public/fonts/Kanit/Kanit-Thin.ttf create mode 100644 public/fonts/Kanit/Kanit-ThinItalic.ttf create mode 100644 public/fonts/Kanit/OFL.txt create mode 100644 public/fonts/Parisienne/OFL.txt create mode 100644 public/fonts/Parisienne/Parisienne-Regular.ttf create mode 100644 public/myevents.ics create mode 100644 public/pattern.svg create mode 100644 public/penguin.svg create mode 100644 seed-data/data.js create mode 100644 seed-data/index.js create mode 100644 styles/Home.module.css create mode 100644 styles/globals.css create mode 100644 utils/db.js create mode 100644 utils/useInterval.js diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..72cb4c6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Launch Program", + "skipFiles": ["/**"], + "port": 9229 + } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..0a24236 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Wedding Website + +## This is a skeleton template of the wedding website I created +## Names, Dates, Locations are all hardcoded to a value + +The site implements a basic auth to protect access without knowing the password to the site. + +## Tech +Overall a typical NextJS Application +### Frontend +- ReactJS +- Styled Components +- Next Iron Session for Login +### Backend +- NextJS APIs +- Mongoose DB for MongoDB + - Used to store RSVPs and default login diff --git a/components/CustomNextCloudinaryImage.js b/components/CustomNextCloudinaryImage.js new file mode 100644 index 0000000..1cb6d40 --- /dev/null +++ b/components/CustomNextCloudinaryImage.js @@ -0,0 +1,81 @@ +import { useEffect, useState } from 'react'; +import Image from 'next/image'; +import { buildUrl } from 'cloudinary-build-url'; +// import wait from 'waait'; +import styled, { keyframes } from 'styled-components'; + +const blurImageTransition = keyframes` + from { + filter: blur(0); + } + to { + + filter: blur(5px) + } +`; + +const unblurImageTransition = keyframes` + from { + filter: blur(5px) + } + to { + filter: blur(0); + } +`; + +const CustomStylesContainer = styled.div` + .unblur { + animation: ${unblurImageTransition} 1s linear; + } + .blur { + animation: ${blurImageTransition} 1s linear; + } +`; + +const CustomNextCloudinaryImage = (props) => { + const { height, width, src, onLoad, blur, resize, ...other } = props; + const [onLoadCount, setOnloadCount] = useState(0); + const [imageLoaded, setImageLoaded] = useState(false); + + const transformations = {}; + + if (resize) { + transformations.resize = { + type: 'scale', + width, + height, + }; + } + + const imageUrl = buildUrl(`${process.env.NEXT_PUBLIC_FOLDER_NAME}/${src}`, { + cloud: { + cloudName: process.env.NEXT_PUBLIC_CLOUD_NAME, + }, + transformations, + }); + + useEffect(() => { + if (onLoadCount > 1) { + setImageLoaded(true); + } + }, [onLoadCount]); + + return ( + + { + setOnloadCount((prev) => prev + 1); + if (onLoad) onLoad(e); + }} + src={imageUrl} + objectFit="cover" + width={width} + height={height} + {...other} + /> + + ); +}; + +export default CustomNextCloudinaryImage; diff --git a/components/CustomNextImage.js b/components/CustomNextImage.js new file mode 100644 index 0000000..375364d --- /dev/null +++ b/components/CustomNextImage.js @@ -0,0 +1,63 @@ +import { useEffect, useState } from 'react'; +import Image from 'next/image'; +import styled, { keyframes } from 'styled-components'; + +const blurImageTransition = keyframes` + from { + filter: blur(0); + } + to { + + filter: blur(5px) + } +`; + +const unblurImageTransition = keyframes` + from { + filter: blur(5px) + } + to { + filter: blur(0); + } +`; + +const CustomStylesContainer = styled.div` + .unblur { + animation: ${unblurImageTransition} 1s linear; + } + .blur { + animation: ${blurImageTransition} 1s linear; + } +`; + + +const CustomNextImage = (props) => { + const { height, width, src, onLoad, ...other } = props; + const [onLoadCount, setOnloadCount] = useState(0); + const [imageLoaded, setImageLoaded] = useState(false); + + useEffect(() => { + if (onLoadCount > 1) { + setImageLoaded(true); + } + }, [onLoadCount]); + + return ( + + { + setOnloadCount((prev) => prev + 1); + if (onLoad) onLoad(e); + }} + src={imageUrl} + objectFit="cover" + width={width} + height={height} + {...other} + /> + + ); +}; + +export default CustomNextImage; diff --git a/components/Event.js b/components/Event.js new file mode 100644 index 0000000..908a81e --- /dev/null +++ b/components/Event.js @@ -0,0 +1,69 @@ +import styled from 'styled-components'; + +const EventStyles = styled.article` + display: grid; + gap: 2rem; + justify-content: center; + margin-top: 3.5rem; + .schedule-event { + padding-bottom: 1rem; + border-bottom: 2px solid var(--lightGrey); + } +`; + +const ScheduleStyle = styled.article` + display: flex; + gap: 1.5rem; + flex-direction: row; + text-align: center; +`; + +export default function Event({ event }) { + const { + name, + date, + start, + end, + venueName, + attire, + description, + openToAll, + showSchedule, + scheduleEvents, + } = event; + return ( + +
+

{name}

+

{date}

+

+ {start} + {end && ` - ${end}`} +

+ {venueName &&
} + {attire &&

{attire}

} + {description &&

{description}

} +
+ {showSchedule && + scheduleEvents && + scheduleEvents.map(({ name, start, end, venueName }) => ( + +
+ {start && ( +

+ {start} + {end && ` - {end}`} +

+ )} +
+
+ {name &&

{name}

} + {venueName && ( +
+ )} +
+ + ))} + + ); +} diff --git a/components/Footer.js b/components/Footer.js new file mode 100644 index 0000000..552e43d --- /dev/null +++ b/components/Footer.js @@ -0,0 +1,75 @@ +import styled from 'styled-components'; +import Link from 'next/link'; +import useUser from '../lib/useUser'; + +const FooterStyles = styled.footer` + display: grid; + grid-template-rows: repeat(2, 1fr); + gap: 1.5rem; + justify-content: center; + align-items: center; + align-content: center; + gap: 1rem; + text-align: center; + + margin-top: 6rem; + + @media (max-width: 800px) { + margin-top: 2rem; + } + + h2 { + font-size: 4rem; + } + + hr { + display: block; + max-width: 50%; + height: 0; + max-height: 0; + border: solid; + width: 100%; + border-width: thin 0 0 0; + transition: inherit; + border-color: var(--lightShade); + color: var(--lightShade); + } + + p { + margin: 0; + padding: 0.2rem; + font-weight: 600; + color: var(--lightShade); + } + + ul { + margin: 0.5rem; + } +`; + +export default function Footer() { + const { user } = useUser(); + + return ( + +
+

+ + N & N + +

+ {user && user.isLoggedIn === true ? ( + <> +
+

06.03.2030

+ + ) : ( + '' + )} +
+
+

Created by Bradley

+
+
+ ); +} diff --git a/components/Form.js b/components/Form.js new file mode 100644 index 0000000..48f678d --- /dev/null +++ b/components/Form.js @@ -0,0 +1,43 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Form = ({ errorMessage, onSubmit }) => ( +
+ + + + + {errorMessage &&

{errorMessage}

} + + +
+); + +export default Form; + +Form.propTypes = { + errorMessage: PropTypes.string, + onSubmit: PropTypes.func, +}; diff --git a/components/GuestRSVP.js b/components/GuestRSVP.js new file mode 100644 index 0000000..28cd94c --- /dev/null +++ b/components/GuestRSVP.js @@ -0,0 +1,118 @@ +import { useState } from 'react'; +import styled from 'styled-components'; +import PlusOneRSVP from './PlusOneRSVP'; + +export const GuestStyles = styled.div` + display: grid; + grid-template-columns: repeat(3, 1fr); + // flex-direction: row; + justify-content: center; + justify-items: center; + align-content: center; + align-items: center; + gap: 1.5rem; + margin: 1rem 0; + h3 { + margin-right: 2rem; + } + + input[type='radio'] { + opacity: 0; + position: fixed; + width: 0; + } + + /* input[type='checkbox'] { + margin: 0; + padding: 0; + } */ + + label { + background: none; + color: var(--lightViolet); + border: 1px solid var(--lightViolet); + padding: 1rem 1.5rem; + border-radius: 4px; + cursor: pointer; + --cast: 2px; + box-shadow: var(--cast) var(--cast) 0 var(--lightAccent); + text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.2); + transition: all 0.2s; + text-decoration: none; + + &:hover { + --cast: 4px; + } + &:active { + --cast: 2px; + } + } + + label:hover { + background-color: var(--lightViolet); + color: var(--black); + } + + input[type='radio']:checked + label { + background: var(--lightViolet); + color: var(--black); + border: 0; + } + + input[type='radio']:focus + label { + background: var(--primary); + color: var(--black); + border: 0; + } +`; + +export default function GuestRSVP({ guest, inputs, handleChange }) { + if (!guest) { + return

Loading...

; + } + + // const [plusOne, setPlusOne] = useState( + // guest?.rsvpStatus === 'accepted' && guest?.plusOne + // ); + + return ( + <> + +

+ {guest.firstName} {guest.lastName} +

+ + + + +
+ {guest?.hasPlusOne && inputs[guest?.id]?.rsvpStatus === 'accepted' ? ( + + ) : ( + '' + )} + + ); +} diff --git a/components/Header.js b/components/Header.js new file mode 100644 index 0000000..5729d7b --- /dev/null +++ b/components/Header.js @@ -0,0 +1,51 @@ +import React from 'react'; +import styled from 'styled-components'; +import Link from 'next/link'; +import useUser from '../lib/useUser'; +import WeddingStart from './WeddingStart'; +import Nav from './Nav'; + +const HeaderStyles = styled.header` + display: grid; + gap: 1.8rem; + margin: 2rem 1.5rem 1rem 1.5rem; + nav { + margin-top: 1.5rem; + } + + @media (max-width: 650px) { + h2 { + font-size: var(--h3); + } + } +`; + +const Header = () => { + const { user, mutateUser } = useUser(); + return ( + +
+ + +

Name & Name

+
+ + {user && user.isLoggedIn === true ? ( + <> +

+ June 3rd, 2030 • New York, New York +

+

+ Countdown: days! +

+ + ) : ( + '' + )} +
+ {user && user.isLoggedIn === true ?