Skip to content

Commit 3e7d2a0

Browse files
committed
Initial app migration
1 parent 539f849 commit 3e7d2a0

File tree

118 files changed

+9134
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+9134
-0
lines changed

.babelrc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"plugins": ["@emotion/babel-plugin", "babel-plugin-transform-glob-import"],
3+
"presets": ["@babel/preset-env", "@babel/preset-react"],
4+
"targets": {
5+
"node": 9
6+
}
7+
}

.parcelrc

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "@parcel/config-default",
3+
"transformers": {
4+
"*.{js,mjs,jsx,cjs,ts,tsx}": [
5+
"@parcel/transformer-js",
6+
"@parcel/transformer-react-refresh-wrap"
7+
]
8+
},
9+
"resolvers": ["@parcel/resolver-glob", "..."]
10+
}

App.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from "react"
2+
import { Router } from "@reach/router"
3+
import "./global-styles/variables.scss"
4+
import "./global-styles/styles.scss"
5+
import Header from "components/header"
6+
import HomePage from "components/page-home"
7+
import AboutPage from "components/page-about"
8+
import ListingsPage from "components/page-listings"
9+
import Listing from "components/page-listing-detail"
10+
import SemanticsExercise from "./exercise1-headings-landmarks/page-listing-detail"
11+
import ARIAExercise from "./exercise2-what-is-aria/page-listing-detail"
12+
import A11yNamingExercise from "./exercise3-accessible-names/page-listing-detail"
13+
import A11yNamingExerciseListings from "./exercise3-accessible-names/page-listings"
14+
import ProgrammaticA11yExercise from "./exercise4-programmatic-a11y-info/page-listing-detail"
15+
16+
import imgFooterLogo from "images/icons/footer-logo.svg"
17+
18+
export function App() {
19+
return <>
20+
<Header />
21+
<main id="main">
22+
<Router>
23+
<HomePage path="/" />
24+
<AboutPage path="/about" />
25+
<ListingsPage path="/listings" />
26+
<Listing path="/listing/:id" />
27+
<SemanticsExercise path="/exercise1/:id" />
28+
<ARIAExercise path="/exercise2/:id" />
29+
<A11yNamingExercise path="/exercise3/:id" />
30+
<A11yNamingExerciseListings path="/exercise3/listings" />
31+
<ProgrammaticA11yExercise path="/exercise4/:id" />
32+
</Router>
33+
</main>
34+
<footer id="footer">
35+
<div className="layout">
36+
<div id="footer-logo">
37+
<img src={imgFooterLogo} alt="CampSpots" />
38+
</div>
39+
</div>
40+
</footer>
41+
</>
42+
}

components/button-submit.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from "react"
2+
3+
const ButtonSubmit = ({buttonName, onClick}) => {
4+
return (
5+
<button
6+
aria-label={buttonName}
7+
className="btn-submit btn-lookingglass"
8+
data-testid="btn-submit"
9+
onClick={(event) => { onClick(event)}}
10+
>
11+
<span className="icon-lookingglass-white"></span>
12+
</button>
13+
)
14+
}
15+
16+
export default ButtonSubmit

components/date-picker/date-picker.js

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import React, { useEffect, useRef, useState } from "react"
2+
import dayjs from 'dayjs'
3+
import weekday from 'dayjs/plugin/weekday'
4+
import weekOfYear from 'dayjs/plugin/weekOfYear'
5+
6+
import { createActiveMonthDays, createPrevMonthDays, createNextMonthDays } from './utils'
7+
import "./date-picker.scss"
8+
9+
const DatePicker = ({monthsInAdvance = 2, currDate}) => {
10+
dayjs.extend(weekday)
11+
dayjs.extend(weekOfYear)
12+
13+
// set date to 3 months from now
14+
let date = new Date()
15+
date.setMonth(date.getMonth() + monthsInAdvance)
16+
17+
// keep the active, visible date in State
18+
let [activeDate, setActiveDate] = useState(dayjs(date))
19+
const startYear = dayjs(activeDate).format("YYYY")
20+
const startMonth = dayjs(activeDate).format("M")
21+
22+
// this collection of dates would come from a database, etc.
23+
let initUnavailableDates = ['2022-04-10', '2022-04-11', '2022-04-12', '2022-04-14', '2022-04-15', '2022-04-17', '2022-04-18', '2022-04-19', '2022-04-24', '2022-04-25', '2022-04-27']
24+
let activeMonthDays = createActiveMonthDays(startYear, startMonth, initUnavailableDates)
25+
let prevMonthDays = createPrevMonthDays(startYear, startMonth, activeMonthDays, initUnavailableDates)
26+
let nextMonthDays = createNextMonthDays(startYear, startMonth, activeMonthDays, initUnavailableDates)
27+
28+
let days = [...prevMonthDays, ...activeMonthDays, ...nextMonthDays]
29+
let [unavailableDates, setUnavailableDates] = useState(initUnavailableDates)
30+
let [selectedDates, setSelectedDates] = useState([])
31+
32+
const setPrevMonth = () => {
33+
// only go backward as far as current month
34+
if (isPrevMonthAvailable()) {
35+
setActiveDate(dayjs(activeDate).subtract(1, "month"))
36+
}
37+
}
38+
const setNextMonth = () => {
39+
setActiveDate(dayjs(activeDate).add(1, "month"))
40+
}
41+
const isPrevMonthAvailable = () => {
42+
return dayjs(activeDate).subtract(1, 'month').get('month') >= dayjs().get('month')
43+
}
44+
const isDayUnavailable = (day) => {
45+
return unavailableDates.includes(day.date)
46+
}
47+
const bookDay = (day) => {
48+
// this function would run on "Reserve"
49+
setUnavailableDates(
50+
unavailableDates => [day.date, ...unavailableDates, `${unavailableDates.length}`]
51+
)
52+
}
53+
const isDaySelected = (day) => {
54+
return selectedDates.includes(day.date)
55+
}
56+
const selectDay = (day) => {
57+
// to-do: consider perf of this for large quanitites of dates
58+
if (!isDayUnavailable(day)) {
59+
// add to selected Dates if not already selected
60+
if (!isDaySelected(day)) {
61+
setSelectedDates(
62+
selectedDates => [day.date, ...selectedDates]
63+
)
64+
} else {
65+
setSelectedDates(
66+
selectedDates.filter(date => date !== day.date)
67+
)
68+
}
69+
}
70+
}
71+
return (
72+
<div className="date-picker">
73+
<header>
74+
<div
75+
className="btn-month btn-prev"
76+
disabled={isPrevMonthAvailable() ? '' : 'disabled'}
77+
onClick={setPrevMonth}
78+
>
79+
<span></span>
80+
{ dayjs(activeDate).subtract(1, "month").format("MMM") }
81+
</div>
82+
<h4>{ dayjs(activeDate).format("MMMM YYYY") }</h4>
83+
<div
84+
className="btn-month btn-next"
85+
onClick={setNextMonth}
86+
>
87+
{ dayjs(activeDate).add(1, 'month').format("MMM") }
88+
<span></span>
89+
</div>
90+
</header>
91+
<div className="days-of-week">
92+
<span title="Sunday">S</span>
93+
<span title="Monday">M</span>
94+
<span title="Tuesday">T</span>
95+
<span title="Wednesday">W</span>
96+
<span title="Thursday">T</span>
97+
<span title="Friday">F</span>
98+
<span title="Saturday">S</span>
99+
</div>
100+
<div className="date-grid">
101+
{days.map((day, index) => {
102+
return <div
103+
className={[
104+
'grid-btn',
105+
day.isBooked ? 'booked' : '',
106+
day.isCurrentMonth ? 'currentMonth' : '',
107+
isDaySelected(day) ? 'selected' : ''
108+
].join(' ').trim()}
109+
key={index}
110+
onClick={() => selectDay(day)}
111+
>
112+
<time date-time={day.date}>{day.dayOfMonth}</time>
113+
<span className="icon" aria-hidden="true"></span>
114+
</div>
115+
})}
116+
</div>
117+
<div className="date-key">
118+
<div className="date-key-item-wrap">
119+
<span className="date-key-item booked">
120+
<span className="icon" aria-hidden="true"></span>
121+
</span>
122+
<span className="date-key-text">Booked</span>
123+
</div>
124+
<div className="date-key-item-wrap">
125+
<span className="date-key-item available">
126+
<span className="icon" aria-hidden="true"></span>
127+
</span>
128+
<span className="date-key-text">Available</span>
129+
</div>
130+
<div className="date-key-item-wrap">
131+
<span className="date-key-item selected">
132+
<span className="icon" aria-hidden="true"></span>
133+
</span>
134+
<span className="date-key-text">Selected</span>
135+
</div>
136+
</div>
137+
<div className="reserve-btn">Reserve</div>
138+
</div>
139+
)
140+
}
141+
142+
export default DatePicker
+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
.date-picker {
2+
width: 100%;
3+
4+
button {
5+
-webkit-appearance: none;
6+
}
7+
8+
header {
9+
align-items: center;
10+
display: flex;
11+
padding: 2em 0;
12+
13+
h4 {
14+
font-weight: 500;
15+
margin: 0 auto;
16+
text-align: center;
17+
}
18+
.btn-month {
19+
background-color: transparent;
20+
border: none;
21+
cursor: pointer;
22+
display: flex;
23+
font-size: 0.8rem;
24+
25+
&.btn-prev span:before {
26+
content: '<';
27+
margin-right: 0.25em;
28+
}
29+
&.btn-next span:after {
30+
content: ' >';
31+
margin-left: 0.25em;
32+
}
33+
}
34+
}
35+
table {
36+
border-spacing: 0;
37+
width: 100%;
38+
}
39+
}
40+
.days-of-week * {
41+
font-weight: normal;
42+
padding: 0.5em;
43+
text-align: center;
44+
}
45+
.days-of-week span {
46+
display: block;
47+
}
48+
div.days-of-week,
49+
div.date-grid {
50+
display: grid;
51+
gap: 0.25em;
52+
grid-template-columns: repeat(7, 1fr);
53+
}
54+
.date-grid .grid-btn {
55+
height: 100%;
56+
width: 100%;
57+
}
58+
.date-grid,
59+
.date-key {
60+
.grid-btn,
61+
.date-key-item {
62+
background-color: var(--bgcolor-date-button);
63+
border: 1px solid var(--color-border-button);
64+
cursor: pointer;
65+
display: block;
66+
font-size: 1rem;
67+
font-weight: bold;
68+
padding: 0.5em 0.25em 0.25em;
69+
70+
span.icon:after {
71+
border-bottom: 2px solid transparent;
72+
content: '';
73+
display: block;
74+
}
75+
}
76+
.grid-btn:not(.currentMonth) {
77+
opacity: 0.4;
78+
}
79+
.grid-btn:not(.currentMonth):not(.booked):not(.selected) {
80+
background-color: transparent;
81+
border: none;
82+
}
83+
.booked {
84+
background-color: var(--bgcolor-datepicker-booked);
85+
border: 1px solid var(--bgcolor-date-button);
86+
color: var(--color-accent-error);
87+
cursor: not-allowed;
88+
position: relative;
89+
90+
span.icon:after {
91+
content: '';
92+
font-size: 0.75rem;
93+
line-height: 1;
94+
margin-right: 0.15em;
95+
position: absolute;
96+
right: 0;
97+
top: 0;
98+
}
99+
}
100+
.selected {
101+
background-color: var(--color-accent-dark);
102+
color: var(--color-primary-light);
103+
104+
span.icon:after {
105+
border-bottom: 2px solid currentColor;
106+
content: '';
107+
display: block;
108+
width: 100%;
109+
}
110+
}
111+
}
112+
.date-key {
113+
display: flex;
114+
flex-direction: row;
115+
justify-content: space-between;
116+
margin: 1em 0;
117+
padding: 0;
118+
119+
.date-key-item-wrap {
120+
align-items: center;
121+
display: flex;
122+
flex-direction: row;
123+
}
124+
.date-key-item {
125+
display: block;
126+
height: 1.25rem;
127+
margin-right: 0.25em;
128+
padding: 0;
129+
width: 1.25rem;
130+
}
131+
span.icon {
132+
cursor: default;
133+
display: flex;
134+
height: 100%;
135+
line-height: 1;
136+
padding: 0;
137+
width: 100%;
138+
}
139+
.selected span.icon:after {
140+
margin: auto 0.15em 0.15em;
141+
width: 100%;
142+
}
143+
.date-key-text {
144+
font-size: 0.9rem;
145+
}
146+
}
147+
.reserve-btn {
148+
background-color: var(--color-accent-dark);
149+
border: none;
150+
border-radius: 5px;
151+
color: var(--color-primary-light);
152+
cursor: pointer;
153+
display: block;
154+
font-family: inherit;
155+
font-size: 1rem;
156+
line-height: 1;
157+
margin-top: 2em;
158+
padding: 1em 0;
159+
text-align: center;
160+
width: 100%;
161+
}

0 commit comments

Comments
 (0)