├── db.json ├── src ├── styles │ ├── Nav.css │ ├── Estimates.css │ ├── Contact.css │ ├── About.css │ └── Header.css ├── media │ └── header-image.jpg ├── pages │ ├── Confirmation.js │ ├── ErrorPage.js │ ├── Estimates.js │ ├── Contact.js │ ├── Appointments.js │ └── About.js ├── setupTests.js ├── App.test.js ├── reportWebVitals.js ├── index.css ├── components │ ├── EstimateList.js │ ├── EstimateChip.js │ ├── UserEdit.js │ ├── RCCard.js │ ├── Footer.js │ ├── RepeatService.js │ ├── UserDetail.js │ ├── EstimateItem.js │ ├── LocationCreate.js │ ├── Header.js │ ├── UserCreate.js │ ├── Nav.js │ ├── Calendar.js │ └── EstimateDetail.js ├── App.css ├── index.js ├── themes │ └── Theme.js ├── App.js ├── constants │ └── EstimateConstants.js ├── logo.svg ├── services │ └── useEstimatesService.js └── context │ └── estimate.js ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── .gitignore ├── package.json └── README.md /db.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/Nav.css: -------------------------------------------------------------------------------- 1 | .Nav { 2 | margin: auto; 3 | text-align: center; 4 | 5 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtime/rc-react-app/master/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtime/rc-react-app/master/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtime/rc-react-app/master/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/media/header-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtime/rc-react-app/master/src/media/header-image.jpg -------------------------------------------------------------------------------- /src/pages/Confirmation.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | const Confirmation = () => { 4 | return ( 5 |
6 |

Confirmation

7 |
8 | ) 9 | } 10 | 11 | 12 | export default Confirmation; -------------------------------------------------------------------------------- /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/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/styles/Estimates.css: -------------------------------------------------------------------------------- 1 | .Estimates { 2 | margin-top: 10px; 3 | margin-bottom: 20px; 4 | padding-bottom: 0; 5 | text-align: left 6 | /*NOTE MARGINS ARE handled.. 1. in app-container disableGutters. 2. set in nav.js Box sx = paddingleft: * ;*/ 7 | /*padding-right: 40px;*/ 8 | } -------------------------------------------------------------------------------- /src/pages/ErrorPage.js: -------------------------------------------------------------------------------- 1 | const ErrorPage = () => { 2 | const error = 404; 3 | return ( 4 |
5 |

Unfortunately our server has returned a ${error} Error. Please check your request and try again

6 |
7 | ) 8 | } 9 | 10 | export default ErrorPage; -------------------------------------------------------------------------------- /src/styles/Contact.css: -------------------------------------------------------------------------------- 1 | .contact { 2 | margin-top: 10px; 3 | margin-bottom: 40px; 4 | padding-bottom: 0; 5 | text-align: left 6 | /*NOTE MARGINS ARE handled.. 1. in app-container disableGutters. 2. set in nav.js Box sx = paddingleft: * ;*/ 7 | /*padding-right: 40px;*/ 8 | 9 | } 10 | 11 | .chat { 12 | min-width: 272px; 13 | height: 420px; 14 | } 15 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: #ff6600; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /src/styles/About.css: -------------------------------------------------------------------------------- 1 | .About { 2 | margin-top: 12px; 3 | margin-bottom: 20px; 4 | padding-bottom: 0; 5 | text-align: left; 6 | /*NOTE MARGINS ARE handled.. 1. in app-container disableGutters. 2. set in nav.js Box sx = paddingleft: * ;*/ 7 | /*padding-right: 40px;*/ 8 | 9 | } 10 | 11 | .h3 { 12 | color: #86b95a; 13 | font-size: 1.25em; 14 | } 15 | 16 | .About-title { 17 | 18 | } 19 | 20 | .About-desc { 21 | margin-bottom: 30px; 22 | } -------------------------------------------------------------------------------- /.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 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | 17 | .env.development 18 | .env.staging 19 | .env.production 20 | .env.local 21 | .env.stage 22 | .env.prod 23 | .env.development.local 24 | .env.test.local 25 | .env.production.local 26 | 27 | npm-debug.log* 28 | yarn-debug.log* 29 | yarn-error.log* 30 | 31 | .idea 32 | 33 | -------------------------------------------------------------------------------- /src/styles/Header.css: -------------------------------------------------------------------------------- 1 | .header { 2 | margin: auto; 3 | } 4 | .img { 5 | /*border: 3px solid #73AD21;*/ 6 | /*width: 1290px;*/ 7 | /*object-fit: cover;*/ 8 | /*background-color: #ffcc00;*/ 9 | } 10 | 11 | .header.title { 12 | margin: auto; 13 | border: 3px solid #73AD21; 14 | /*padding: 10px;*/ 15 | /* text-align: center;* 16 | } 17 | 18 | .header.subtitle { 19 | /*line-height: 1.5;*/ 20 | } 21 | 22 | .header.body { 23 | /*font-style: italic;*/ 24 | margin-bottom: 24px; 25 | /*font-family: "Arial";*/ 26 | /*font-size: large;*/ 27 | /*line-height: 24px;*/ 28 | } -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "RapidClean", 3 | "name": "RapidClean Cleaning Service", 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 | -------------------------------------------------------------------------------- /src/components/EstimateList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import EstimateItem from './EstimateItem'; 4 | 5 | import { 6 | Box, 7 | ImageList, 8 | ImageListItem, Typography 9 | } from '@mui/material'; 10 | 11 | const EstimateList = ({ estimates }) => { 12 | //console.log('[EstimateList] estimates : ', estimates); 13 | const renderedList = estimates.map((estimate) => { 14 | return 15 | }) 16 | return ( 17 | 18 | 19 | estimates list 20 | 21 | {renderedList} 24 | 25 | ) 26 | // return
EstimateList
27 | } 28 | 29 | export default EstimateList; -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; 3 | font-weight: 300; 4 | color: grey; 5 | text-align: center; 6 | background-color: #e4f2ff; 7 | 8 | 9 | } 10 | 11 | 12 | .App-logo { 13 | /*height: 40vmin;*/ 14 | /*pointer-events: none;*/ 15 | /*max-width: 150px;*/ 16 | } 17 | 18 | @media (prefers-reduced-motion: no-preference) { 19 | .App-logo { 20 | animation: App-logo-spin infinite 20s linear; 21 | } 22 | } 23 | 24 | .App-header { 25 | /*background-color: #E4F0F9;*/ 26 | /*min-height: 100vh;*/ 27 | /*display: flex;*/ 28 | /*flex-direction: column;*/ 29 | /*align-items: center;*/ 30 | /*justify-content: center;*/ 31 | /*font-size: calc(10px + 2vmin);*/ 32 | /*color: white;*/ 33 | } 34 | 35 | .App-link { 36 | color: #61dafb; 37 | } 38 | 39 | @keyframes App-logo-spin { 40 | from { 41 | transform: rotate(0deg); 42 | } 43 | to { 44 | transform: rotate(360deg); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import { Provider } from './context/estimate' 6 | //import reportWebVitals from './reportWebVitals'; 7 | 8 | 9 | //CONTEXT PROVIDER WRAPS APP (./context/estimate.js) and acts as a public interfaace to components by injecting functions and states into the app. 10 | // pages and components will use the methods in the context to create and edit and the context will 11 | // handle the axios calls and state and pass down to children. children import specific functions and data as needed 12 | 13 | 14 | const root = ReactDOM.createRoot(document.getElementById('root')); 15 | root.render( 16 | 17 | 18 | 19 | ); 20 | 21 | // If you want to start measuring performance in your app, pass a function 22 | // to log results (for example: reportWebVitals(console.log)) 23 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 24 | //reportWebVitals(); 25 | -------------------------------------------------------------------------------- /src/components/EstimateChip.js: -------------------------------------------------------------------------------- 1 | import {Chip} from "@mui/material"; 2 | import React from "react"; 3 | 4 | const EstimateChip = ({total}) => { 5 | //console.log('[EstimateChip] num input: ', total) 6 | return( 7 | 28 | ) 29 | } 30 | 31 | export default EstimateChip -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rc-react-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@calcom/embed-react": "^1.5.0", 7 | "@emotion/react": "^11.13.3", 8 | "@emotion/styled": "^11.13.0", 9 | "@mui/icons-material": "^5.16.7", 10 | "@mui/material": "^5.16.7", 11 | "@testing-library/jest-dom": "^5.17.0", 12 | "@testing-library/react": "^13.4.0", 13 | "@testing-library/user-event": "^13.5.0", 14 | "axios": "^1.7.2", 15 | "formik": "^2.4.6", 16 | "formik-material-ui": "^4.0.0-alpha.2", 17 | "json-server": "^0.17.4", 18 | "mui-image": "^1.0.7", 19 | "react": "^18.3.1", 20 | "react-dom": "^18.3.1", 21 | "react-scripts": "5.0.1", 22 | "web-vitals": "^2.1.4", 23 | "yup": "^1.4.0" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build:dev": "env-cmd -f .env.development react-scripts build", 28 | "build:stage": "env-cmd -f .env.staging react-scripts build", 29 | "build:prod": "env-cmd -f .env.production react-scripts build", 30 | "eject": "react-scripts eject", 31 | "clean": "rm -rf build/*" 32 | 33 | }, 34 | "eslintConfig": { 35 | "extends": [ 36 | "react-app", 37 | "react-app/jest" 38 | ] 39 | }, 40 | "browserslist": { 41 | "production": [ 42 | ">0.2%", 43 | "not dead", 44 | "not op_mini all" 45 | ], 46 | "development": [ 47 | "last 1 chrome version", 48 | "last 1 firefox version", 49 | "last 1 safari version" 50 | ] 51 | }, 52 | "devDependencies": { 53 | "env-cmd": "^10.1.0", 54 | "react-router-dom": "^6.23.1" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/components/UserEdit.js: -------------------------------------------------------------------------------- 1 | import React, {useState, useContext, useEffect } from 'react'; 2 | import '../styles/Estimates.css'; 3 | import * as Constants from '../constants/EstimateConstants'; 4 | import EstimateContext from '../context/estimate'; 5 | 6 | import { 7 | Typography, Grid, Box, Button, 8 | ThemeProvider, CssBaseline, Card, 9 | CardContent, CardActions, 10 | FormControl, Select, MenuItem, InputLabel, FormControlLabel, Checkbox, 11 | } from '@mui/material'; 12 | 13 | import { Formik, Form } from "formik"; 14 | 15 | import { RapidCleanTheme } from "../themes/Theme.js"; 16 | import * as Yup from "yup"; 17 | 18 | const EditUser =({user}) => { 19 | 20 | //todo MUST ADD ON SUBMIT TO THE PARAM ABOVE FOR THIS PARADIGM TO WORK 21 | //onSubmit 22 | 23 | const { editUserById } = useContext(EstimateContext); 24 | // get edit func from provider as well as onSubmit to pass event with data up 25 | 26 | //this is correct 27 | //console.log('[EditUser] user: , ', user) 28 | 29 | // removing the servicedetails wrapper (to use calculateEstimate) but storing the id which sits outside of it 30 | // const initialValues = user.userdetails.id; 31 | //const id = user.userdetails.id; 32 | 33 | //console.log('[EditUser] initialValues: ' , initialValues) 34 | 35 | const handleSubmit = (values) => { 36 | //console.log('[editUser] handleSubmit:', values); 37 | //onSubmit() 38 | //editUserById(id, values); 39 | } 40 | 41 | return ( 42 | 43 | <> 44 |
UserEdit
45 | todo Formik initial values need to have a onsubmit event to pass data up to provider 46 | {/**/} 52 | 53 | ); 54 | } 55 | 56 | export default EditUser; -------------------------------------------------------------------------------- /src/themes/Theme.js: -------------------------------------------------------------------------------- 1 | import { createTheme } from "@mui/material/styles"; 2 | 3 | 4 | export const RapidCleanTheme = createTheme({ 5 | palette: { 6 | primary: { 7 | main: '#3366cc', //2C82FF 8 | }, 9 | secondary: { 10 | main: '#86b95a', 11 | } , 12 | }, 13 | typography: { 14 | cardTitle: { 15 | fontSize: '1.25rem', 16 | fontWeight: 600, 17 | color: '#0885f2', 18 | }, 19 | // Disable h3 variant 20 | 21 | components: { 22 | MuiTypography: { 23 | defaultProps: { 24 | variantMapping: { 25 | // Map the new variant to render a

by default 26 | poster: 'h1', 27 | }, 28 | }, 29 | }, 30 | }, 31 | h1: { 32 | fontSize: '2.5rem', 33 | fontFamily: "Helvetica", 34 | fontWeight: 600, 35 | 36 | }, 37 | h2: { 38 | fontSize: '2rem', 39 | fontFamily: "Helvetica", 40 | fontWeight: 600, 41 | }, 42 | h3: { 43 | fontSize: '1.25rem', 44 | fontFamily: "Helvetica", 45 | fontWeight: 600, 46 | color: '#3366cc', 47 | marginBottom: '1rem' 48 | }, 49 | h4: { 50 | fontSize: '1rem', 51 | fontFamily: "Helvetica", 52 | fontWeight: 600, 53 | color: '#86b95a', 54 | marginBottom: '.5rem' 55 | 56 | }, 57 | h5: { 58 | fontSize: '.65rem', 59 | fontFamily: "Helvetica", 60 | fontWeight: 600, 61 | color: '#999999', 62 | }, 63 | h6: { 64 | fontSize: '.5rem', 65 | fontFamily: "Helvetica", 66 | fontWeight: 600, 67 | 68 | } 69 | 70 | }, 71 | button: { 72 | color: 'white', 73 | }, 74 | }); 75 | 76 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 16 | 17 | 21 | 22 | 31 | 35 | RapidClean 36 | 37 | 38 | 39 |
40 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import { 3 | Box, Container, 4 | } from '@mui/material'; 5 | import { RapidCleanTheme } from "./themes/Theme.js"; 6 | // import '@fontsource/roboto/300.css'; 7 | // import '@fontsource/roboto/400.css'; 8 | // import '@fontsource/roboto/500.css'; 9 | // import '@fontsource/roboto/700.css'; 10 | 11 | import React, {useState, useEffect} from 'react'; 12 | import { BrowserRouter, Routes, Route } from "react-router-dom"; 13 | import Nav from './components/Nav'; 14 | import Header from './components/Header'; 15 | import About from './pages/About'; 16 | import Estimates from './pages/Estimates'; 17 | import Appointments from './pages/Appointments'; 18 | import Contact from "./pages/Contact"; 19 | import ErrorPage from "./pages/ErrorPage"; 20 | import Footer from "./components/Footer"; 21 | import EstimateContext from "./context/estimate"; 22 | 23 | 24 | function App() { 25 | 26 | 27 | // fetch if there is data to load into the components below we would do this now 28 | // const { fetchSomeData } = useContext(EstimateContext); 29 | 30 | // Since there isn't currently we let the estimate handle importing context at the estimate component level. 31 | // note pages are static wrappers and for now do not use context. 32 | 33 | return ( 34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 | }> 45 | } /> 46 | } /> 47 | } /> 48 | } /> 49 | } /> 50 | 51 | 52 | 53 | 54 | 55 |