= ({
12 | children,
13 | showNav = true,
14 | fluid = false,
15 | }) => {
16 | return (
17 |
5 |
6 | const ScrollToTopComponent: FC = ({
7 | children = null,
8 | location: { pathname },
9 | }: P) => {
10 | useEffect(() => {
11 | window.scrollTo(0, 0)
12 | }, [pathname])
13 |
14 | // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/33006
15 | return <>{children}>
16 | }
17 |
18 | export const ScrollToTop = withRouter(ScrollToTopComponent)
19 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "react"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/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 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/utils/formUtils.js:
--------------------------------------------------------------------------------
1 | export const emailIsValid = email => {
2 | return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
3 | }
4 |
5 | export const encode = data => {
6 | return Object.keys(data)
7 | .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
8 | .join('&')
9 | }
10 |
11 | export const isEmpty = obj => {
12 | for (const prop in obj) {
13 | if (obj.hasOwnProperty(prop)) return false
14 | }
15 |
16 | return true
17 | }
18 |
19 | export const isFunction = functionToCheck => {
20 | return (
21 | functionToCheck && {}.toString.call(functionToCheck) === '[object Function]'
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/packages/theme/src/Container.js:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components'
2 |
3 | export const Container = styled.div`
4 | width: 100%;
5 | margin-right: auto;
6 | margin-left: auto;
7 |
8 | ${({ fluid }) =>
9 | !fluid &&
10 | css`
11 | padding-right: 15px;
12 | padding-left: 15px;
13 |
14 | @media (min-width: 576px) {
15 | max-width: 540px;
16 | }
17 |
18 | @media (min-width: 768px) {
19 | max-width: 720px;
20 | }
21 |
22 | @media (min-width: 992px) {
23 | max-width: 960px;
24 | }
25 |
26 | @media (min-width: 1200px) {
27 | max-width: ${props => props.theme.maxContainerWidth};
28 | }
29 | `}
30 | `
31 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "independent",
3 | "npmClient": "yarn",
4 | "useWorkspaces": true,
5 | "command": {
6 | "version": {
7 | "message": "chore(release): publish",
8 | "conventionalCommits": true,
9 | "noCommitHooks": true,
10 | "changelogPreset": "conventional-changelog-angular-emoji",
11 | "allowBranch": "master"
12 | },
13 | "publish": {
14 | "yes": true,
15 | "conventionalCommits": true,
16 | "noCommitHooks": true,
17 | "changelogPreset": "conventional-changelog-angular-emoji",
18 | "allowBranch": "master"
19 | }
20 | },
21 | "ignoreChanges": [
22 | "**/__fixtures__/**",
23 | "**/__tests__/**",
24 | "**/__mocks__/**",
25 | "**/*fixture.js",
26 | "**/*.md"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/.vscode/ecommerce-stripe.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "../"
5 | }
6 | ],
7 | "settings": {
8 | "workbench.colorCustomizations": {
9 | "titleBar.activeBackground": "#32325D",
10 | "titleBar.activeForeground": "#ffffff",
11 | "titleBar.inactiveBackground": "#32325D",
12 | "titleBar.inactiveForeground": "#ffffff"
13 | },
14 | "search.exclude": {
15 | "**/node_modules": true,
16 | "**/projects/*/dist": true,
17 | "**/packages/*/dist": true,
18 | "**/projects/*/build": true,
19 | "**/packages/*/build": true,
20 | "**/projects/*/coverage": true,
21 | "**/packages/*/coverage": true
22 | },
23 | "files.exclude": {
24 | "**/projects/caldera*": true
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.vscode/caldera-platform.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "../"
5 | }
6 | ],
7 | "settings": {
8 | "workbench.colorCustomizations": {
9 | "titleBar.activeBackground": "#0080ee",
10 | "titleBar.activeForeground": "#ffffff",
11 | "titleBar.inactiveBackground": "#0080ee",
12 | "titleBar.inactiveForeground": "#ffffff"
13 | },
14 | "search.exclude": {
15 | "**/node_modules": true,
16 | "**/build": true,
17 | "**/projects/*/dist": true,
18 | "**/packages/*/dist": true,
19 | "**/projects/*/build": true,
20 | "**/packages/*/build": true,
21 | "**/projects/*/coverage": true,
22 | "**/packages/*/coverage": true
23 | },
24 | "files.exclude": {
25 | "**/projects/ecommerce-stripe*": true,
26 | "**/build": true
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/theme/src/media.js:
--------------------------------------------------------------------------------
1 | import { css } from 'styled-components'
2 |
3 | const sizes = {
4 | forSmallOnly: {
5 | max: true,
6 | width: 680,
7 | },
8 | forSmallMediumOnly: {
9 | max: true,
10 | width: 991,
11 | },
12 | forMediumUp: {
13 | max: false,
14 | width: 681,
15 | },
16 | forLargeUp: {
17 | max: false,
18 | width: 992,
19 | },
20 | }
21 |
22 | // Iterate through the sizes and create a media template
23 | export const media = Object.keys(sizes).reduce((acc, label) => {
24 | acc[label] = (...args) => {
25 | if (sizes[label].max) {
26 | return css`
27 | @media (max-width: ${sizes[label].width / 16}em) {
28 | ${css(...args)};
29 | }
30 | `
31 | }
32 | return css`
33 | @media (min-width: ${sizes[label].width / 16}em) {
34 | ${css(...args)};
35 | }
36 | `
37 | }
38 |
39 | return acc
40 | }, {})
41 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export type Product = {
2 | id: string
3 | title: string
4 | rating: number
5 | console: string
6 | cover: string
7 | cover_alt: string
8 | quantity: number
9 | quantity_sold: number
10 | price: number
11 | description: string
12 | received_by: string
13 | comments: string
14 | }
15 |
16 | export type ProductShort = {
17 | id: string
18 | title: string
19 | rating: number
20 | console: string
21 | cover: string
22 | cover_alt: string
23 | price: number
24 | description: string
25 | comments: string
26 | }
27 |
28 | export type User = {
29 | cart: ProductShort[]
30 | purchases: any
31 | userId: string
32 | joined: string
33 | email: string
34 | displayName: string
35 | firstName: string
36 | lastName: string
37 | photoURL: string
38 | phoneNumber: string
39 | stripeCharges: any[]
40 | stripeCustomerID: string
41 | }
42 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | rules: {
3 | // 'body-leading-blank': [1, 'always'],
4 | // 'footer-leading-blank': [1, 'always'],
5 | // 'header-max-length': [2, 'always', 72],
6 | // 'scope-case': [2, 'always', 'lower-case'],
7 | // 'subject-case': [
8 | // 2,
9 | // 'never',
10 | // ['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
11 | // ],
12 | // 'subject-empty': [2, 'never'],
13 | // 'subject-full-stop': [2, 'never', '.'],
14 | // 'type-case': [2, 'always', 'lower-case'],
15 | // 'type-empty': [2, 'never'],
16 | 'type-enum': [
17 | 2,
18 | 'always',
19 | [
20 | 'build',
21 | 'chore',
22 | 'ci',
23 | 'docs',
24 | 'feat',
25 | 'fix',
26 | 'perf',
27 | 'refactor',
28 | 'revert',
29 | 'style',
30 | 'test',
31 | ],
32 | ],
33 | },
34 | }
35 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "arrow-body-style": ["off"],
4 | "comma-dangle": ["off"],
5 | "class-methods-use-this": ["off"],
6 | "no-invalid-this": ["off"],
7 | "import/no-named-as-default": ["off"],
8 | "quotes": [2, "single"],
9 | "no-console": ["off"],
10 | "import/no-nodejs-modules": ["off"],
11 | "import/prefer-default-export": ["off"],
12 | "import/no-namespace": ["off"],
13 | "import/noextraneous-dependencies": ["off"],
14 | "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
15 | "no-sync": ["off", { "allowRootLevel": true }],
16 | "jest/no-disabled-tests": ["off"]
17 | },
18 | "extends": [
19 | "node",
20 | "react-app",
21 | "plugin:import/errors",
22 | "plugin:import/warnings",
23 | "plugin:prettier/recommended",
24 | "plugin:jest/recommended"
25 | ],
26 | "plugins": ["jest", "import"],
27 | "globals": {
28 | "jest": true
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true,
3 | "editor.codeActionsOnSaveTimeout": 4000,
4 | "cSpell.words": [
5 | "BITBUCKET",
6 | "Netlify",
7 | "Workspaces",
8 | "accu",
9 | "antd",
10 | "authed",
11 | "brainhubeu",
12 | "browserslist",
13 | "cloudinary",
14 | "disqus",
15 | "dribbble",
16 | "dubnium",
17 | "duplicative",
18 | "ecommerce",
19 | "editorconfig",
20 | "firebaseui",
21 | "fiverr",
22 | "formik",
23 | "lerna",
24 | "linkedin",
25 | "merp",
26 | "narative",
27 | "nohoist",
28 | "noopener",
29 | "noreferrer",
30 | "novela",
31 | "onstatechange",
32 | "onupdatefound",
33 | "potm",
34 | "prettierrc",
35 | "prismjs",
36 | "repo",
37 | "roboto",
38 | "signin",
39 | "smedium",
40 | "spammy",
41 | "svgr",
42 | "svgs",
43 | "unmount",
44 | "weve"
45 | ],
46 | "cSpell.allowCompoundWords": true
47 | }
48 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/style/theme.js:
--------------------------------------------------------------------------------
1 | export const theme = {
2 | maxContainerWidth: '1080px',
3 | darkGray: '#4d4d4d',
4 | defaultFont: '"Roboto", sans-serif',
5 | defaultHeaderFont: '"Palanquin", sans-serif',
6 | defaultFontColor: '#383735',
7 | defaultFontSize: '16px',
8 | defaultParagraphLineHeight: '1.5',
9 | defaultHeaderColor: '#000000',
10 | defaultInputBackgroundColor: '#f5f5f5',
11 | defaultMobileFontSize: '16px',
12 | defaultTransition: 'all 0.2s linear',
13 | desktopHeaderHeight: '75px',
14 | disabledColor: '#888888',
15 | errorColor: '#e44100',
16 | focusColor: '#0080EE',
17 | grayText: '#707070',
18 | lightGray: '#B3B3B3',
19 | linkColor: '#0080EE',
20 | mobileHeaderHeight: '60px',
21 | primaryColor: '#0080EE',
22 | secondaryColor: '#f57e58',
23 | hoveredSecondaryColor: '#fc9a7c',
24 | pressedSecondaryColor: '#fc9a7c',
25 | lightBackgroundColor: '#EDF6FE',
26 | borderBlurColor: '#CFE7EE',
27 | white: '#ffffff',
28 | bodyBackgroundColor: '#ffffff !important',
29 | }
30 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-shared/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/ecommerce-stripe-shared",
3 | "version": "0.2.4",
4 | "description": "Shared code between server and client",
5 | "homepage": "https://github.com/caldera-digital/platform#readme",
6 | "bugs": {
7 | "url": "https://github.com/caldera-digital/platform/issues"
8 | },
9 | "publishConfig": {
10 | "access": "public"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/caldera-digital/platform.git"
15 | },
16 | "main": "dist/index.js",
17 | "module": "dist/index.module.js",
18 | "scripts": {
19 | "build": "rollup -c rollup.config.js",
20 | "clean": "run-p clean:*",
21 | "clean:build": "rimraf dist",
22 | "clean:node_modules": "rimraf node_modules",
23 | "dev": "rollup -c rollup.config.js -w",
24 | "lint": "eslint src/**/*.js",
25 | "lint:fix": "eslint src/**/*.js --fix",
26 | "test": "echo 'No tests, coming soon!'"
27 | },
28 | "devDependencies": {
29 | "@caldera-digital/rollup-config": "^1.0.3"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/pages/LoginPage/LoginPage.tsx:
--------------------------------------------------------------------------------
1 | import * as firebaseui from 'firebaseui'
2 | import React from 'react'
3 | import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'
4 |
5 | import { PageWrapper } from '../../components'
6 | import firebase from '../../config/firebase'
7 | import { APP_NAME } from '../../utils/const'
8 |
9 | // Configure FirebaseUI.
10 | const uiConfig = {
11 | // Popup signin flow rather than redirect flow.
12 | signInFlow: 'popup',
13 | // Redirect to /signedIn after sign in is successful. Alternatively you can provide a callbacks.signInSuccess function.
14 | signInSuccessUrl: '/',
15 | credentialHelper: firebaseui.auth.CredentialHelper.NONE,
16 | signInOptions: [firebase.auth.EmailAuthProvider.PROVIDER_ID],
17 | }
18 |
19 | export const LoginPage: React.FC = () => {
20 | return (
21 |
22 | {APP_NAME}
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/ecommerce-stripe-server",
3 | "version": "0.2.4",
4 | "scripts": {
5 | "clean": "run-p clean:*",
6 | "clean:build": "rimraf dist",
7 | "clean:node_modules": "rimraf node_modules",
8 | "lint": "eslint src/**/*.{ts,tsx,js}",
9 | "lint:fix": "eslint src/**/*.{ts,tsx,js} --fix",
10 | "build": "tsc",
11 | "dev": "npm run build && firebase serve --only functions",
12 | "shell": "npm run build && firebase functions:shell",
13 | "start": "npm run shell",
14 | "deploy": "firebase deploy",
15 | "logs": "firebase functions:log",
16 | "test": "echo 'No tests, coming soon!'",
17 | "init-db": "node ./init-db.js"
18 | },
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "engines": {
23 | "node": "10"
24 | },
25 | "main": "lib/index.js",
26 | "dependencies": {
27 | "@caldera-digital/ecommerce-stripe-shared": "^0.2.4",
28 | "firebase-admin": "^8.4.0",
29 | "firebase-functions": "^3.2.0",
30 | "lodash": "^4.17.15",
31 | "stripe": "^7.8.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
3 |
4 | import { PrivateRoute, ScrollToTop } from './components'
5 | import { CartPage } from './pages/CartPage/CartPage'
6 | import { HomePage } from './pages/HomePage/HomePage'
7 | import { LoginPage } from './pages/LoginPage/LoginPage'
8 | import { NoMatchPage } from './pages/NoMatch/NoMatch'
9 | import { ThankYouPage } from './pages/ThankYou/ThankYou'
10 |
11 | const App: React.FC = () => {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | export default App
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Marcus Wood
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/projects/caldera-www/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Gatsbyjs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/index.tsx:
--------------------------------------------------------------------------------
1 | // Replace this line with polyfills import for browser support
2 | import 'normalize.css'
3 |
4 | import { GlobalStyle } from '@caldera-digital/theme'
5 | import React from 'react'
6 | import ReactDOM from 'react-dom'
7 | import { StripeProvider } from 'react-stripe-elements'
8 | import { ThemeProvider } from 'styled-components'
9 |
10 | import App from './App'
11 | import { AuthProvider } from './context/AuthContext'
12 | import * as serviceWorker from './serviceWorker'
13 | import { THEME } from './utils/theme'
14 |
15 | ReactDOM.render(
16 |
17 | {/* This is the test apiKey! */}
18 |
19 |
20 | <>
21 |
22 |
23 | >
24 |
25 |
26 | ,
27 | document.getElementById('root'),
28 | )
29 |
30 | // If you want your app to work offline and load faster, you can change
31 | // unregister() to register() below. Note this comes with some pitfalls.
32 | // Learn more about service workers: https://bit.ly/CRA-PWA
33 | serviceWorker.unregister()
34 |
--------------------------------------------------------------------------------
/packages/core/src/Loading.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | const LoadingContainer = styled.div`
5 | position: absolute;
6 | left: 50%;
7 | top: 50%;
8 | transform: translate(-50%, -50%);
9 | `
10 |
11 | const StyledLoading = styled.div`
12 | height: 0;
13 | width: 0;
14 | padding: ${({ size }) => {
15 | if (size === 'large') {
16 | return '9px'
17 | } else if (size === 'medium') {
18 | return '6px'
19 | }
20 | return '3px'
21 | }};
22 | border: ${({ size }) => {
23 | let borderSize
24 | if (size === 'large') {
25 | borderSize = '6px'
26 | } else if (size === 'medium') {
27 | borderSize = '5px'
28 | } else {
29 | borderSize = '4px'
30 | }
31 |
32 | return `${borderSize} solid #ccc`
33 | }};
34 | border-right-color: #888;
35 | border-radius: 50%;
36 | animation: rotate 1s infinite linear;
37 |
38 | @keyframes rotate {
39 | /* 100% keyframe for clockwise.
40 | use 0% instead for anticlockwise */
41 | 100% {
42 | transform: rotate(360deg);
43 | }
44 | }
45 | `
46 |
47 | export const Loading = ({ size = 'small' }) => (
48 |
49 |
50 |
51 | )
52 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/hooks/useAuth.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | import firebase from '../config/firebase'
4 |
5 | const db = firebase.firestore()
6 |
7 | export interface AuthState {
8 | isAuthed: boolean
9 | loading: boolean
10 | user?: firebase.User
11 | logout?: () => void
12 | }
13 |
14 | export const defaultAuthState: AuthState = {
15 | isAuthed: false,
16 | loading: true,
17 | }
18 |
19 | export const useAuth = (): AuthState => {
20 | const [authState, setAuthState] = useState(defaultAuthState)
21 |
22 | useEffect(
23 | () =>
24 | firebase.auth().onAuthStateChanged(user => {
25 | if (user) {
26 | setAuthState({ isAuthed: true, user, loading: false })
27 | } else {
28 | setAuthState({ isAuthed: false, loading: false, user: undefined })
29 | }
30 | }),
31 | [],
32 | )
33 |
34 | /**
35 | * Why no setState here? Because the above effect subscription will fire and take care of everything for us.
36 | * Redirects will automatically be handle via PrivateRoute so that users aren't always redirected in case they're
37 | * on a public page.
38 | */
39 | const logout = (): Promise => firebase.auth().signOut()
40 |
41 | return { ...authState, logout }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/nav/src/Nav.fixture.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Nav } from './Nav'
3 | import {
4 | CalderaDigitalThemeProvider,
5 | CalderaDigitalThemeConsumer,
6 | } from '@caldera-digital/theme'
7 | import { ThemeProvider } from 'styled-components'
8 |
9 | export default (
10 |
11 |
12 | {theme => (
13 |
14 | console.log('on click called', data),
21 | anotherProp: 'anotherProp',
22 | },
23 | {
24 | route: '/anchor',
25 | text: 'anchor',
26 | as: 'a',
27 | },
28 | {
29 | route: '/selected',
30 | text: 'selected',
31 | as: 'a',
32 | selected: true,
33 | },
34 | ]}
35 | renderLeftSection={() => hello
}
36 | containerClassName="testClassName"
37 | />
38 |
39 | )}
40 |
41 |
42 | )
43 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/rawSvgs/clients/cam-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/theme/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/theme",
3 | "version": "1.0.6",
4 | "description": "Rollup config used by Caldera Digital",
5 | "keywords": [
6 | "caldera digital"
7 | ],
8 | "homepage": "https://github.com/caldera-digital/platform#readme",
9 | "bugs": {
10 | "url": "https://github.com/caldera-digital/platform/issues"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/caldera-digital/platform.git"
15 | },
16 | "publishConfig": {
17 | "access": "public"
18 | },
19 | "license": "MIT",
20 | "main": "dist/index.js",
21 | "module": "dist/index.module.js",
22 | "scripts": {
23 | "build": "rollup -c rollup.config.js",
24 | "clean": "run-p clean:*",
25 | "clean:build": "rimraf dist",
26 | "clean:node_modules": "rimraf node_modules",
27 | "dev": "rollup -c rollup.config.js -w",
28 | "preinstall": "npx use-yarn",
29 | "lint": "eslint src/**/*.js",
30 | "lint:fix": "eslint src/**/*.js --fix",
31 | "test": "echo 'No tests, coming soon!'"
32 | },
33 | "husky": {
34 | "hooks": {
35 | "pre-push": "yarn lint"
36 | }
37 | },
38 | "devDependencies": {
39 | "@caldera-digital/rollup-config": "^1.0.3"
40 | },
41 | "peerDependencies": {
42 | "react": "16.8.6",
43 | "react-dom": "16.8.6",
44 | "styled-components": "4.2.0"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/html.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | export default function HTML(props) {
5 | return (
6 |
7 |
8 |
9 |
10 |
14 |
18 | {props.headComponents}
19 |
20 |
21 | {props.preBodyComponents}
22 |
23 | This app works best with JavaScript enabled.
24 |
25 |
30 | {props.postBodyComponents}
31 |
32 |
33 | )
34 | }
35 |
36 | HTML.propTypes = {
37 | htmlAttributes: PropTypes.object,
38 | headComponents: PropTypes.array,
39 | bodyAttributes: PropTypes.object,
40 | preBodyComponents: PropTypes.array,
41 | body: PropTypes.string,
42 | postBodyComponents: PropTypes.array,
43 | }
44 |
--------------------------------------------------------------------------------
/projects/caldera-www/static/_redirects:
--------------------------------------------------------------------------------
1 | /blog/we-launched-a-product-with-150-here-s-what-happened https://www.marcuswood.io/blog/we-launched-a-product-with-150-here-s-what-happened 301
2 | /blog/announcing-guess-the-throne-a-game-of-thrones-death-pool https://www.marcuswood.io/blog/announcing-guess-the-throne-a-game-of-thrones-death-pool 301
3 | /blog/the-non-techie-s-guide-to-creating-a-successful-app https://www.marcuswood.io/blog/the-non-techie-s-guide-to-creating-a-successful-app 301
4 | /blog/beginning-your-web-development-journey-start-here https://www.marcuswood.io/blog/beginning-your-web-development-journey-start-here 301
5 | /blog/supercharge-your-workflow-with-profiles-and-arrangements https://www.marcuswood.io/blog/supercharge-your-workflow-with-profiles-and-arrangements 301
6 | /blog/what-s-more-important-process-or-results https://www.marcuswood.io/blog/what-s-more-important-process-or-results 301
7 | /blog/did-you-know-responsive-images-require-just-an-image-tag-and-two-attributes https://www.marcuswood.io/blog/did-you-know-responsive-images-require-just-an-image-tag-and-two-attributes 301
8 | /case-studies/its-a-date https://www.marcuswood.io/products/its-a-date 301
9 | /case-studies/pride-of-the-meadows https://www.marcuswood.io/products/pride-of-the-meadows 301
10 | /case-studies/guess-the-throne https://www.marcuswood.io/products/guess-the-throne 301
11 | /case-studies/gamebyrd https://www.marcuswood.io/products/gamebyrd 301
12 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/blue-blob3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-server/init-db.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 | const {
3 | FIREBASE_CONFIG,
4 | GAMES,
5 | } = require('@caldera-digital/ecommerce-stripe-shared')
6 | // eslint-disable-next-line import/no-extraneous-dependencies
7 | const firestoreService = require('firestore-export-import')
8 | const serviceAccount = require('./service-account-key.json')
9 |
10 | /**
11 | * Firestore expects a particular format in order for it to seed correctly and be queryable by id.
12 | * Here, we prep all the fixture data so it can go into the DB.
13 | *
14 | * If you need to delete the collections, you have to do that from the Firebase console for now.
15 | */
16 | const data = {
17 | products: {},
18 | }
19 |
20 | GAMES.forEach(game => {
21 | data.products[game.id] = game
22 | })
23 |
24 | // JSON To Firestore
25 | const jsonToFirestore = async () => {
26 | console.warn(
27 | 'This does not truncate existing data! You need to use the console for that because Firebase does not have an easy helper.',
28 | )
29 |
30 | try {
31 | console.log('Initialzing Firebase')
32 | await firestoreService.initializeApp(
33 | serviceAccount,
34 | FIREBASE_CONFIG.databaseURL,
35 | )
36 | console.log('Firebase Initialized')
37 |
38 | await firestoreService.restore(data)
39 | console.log('Upload Success')
40 | } catch (error) {
41 | console.log(error)
42 | }
43 | }
44 |
45 | jsonToFirestore()
46 |
--------------------------------------------------------------------------------
/packages/nav/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/nav",
3 | "version": "1.0.10",
4 | "description": "Fixed navbar component",
5 | "keywords": [
6 | "caldera digital"
7 | ],
8 | "homepage": "https://github.com/caldera-digital/platform#readme",
9 | "bugs": {
10 | "url": "https://github.com/caldera-digital/platform/issues"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/caldera-digital/platform.git"
15 | },
16 | "publishConfig": {
17 | "access": "public"
18 | },
19 | "license": "MIT",
20 | "main": "dist/index.js",
21 | "module": "dist/index.module.js",
22 | "scripts": {
23 | "build": "rollup -c rollup.config.js",
24 | "clean": "run-p clean:*",
25 | "clean:build": "rimraf dist",
26 | "clean:node_modules": "rimraf node_modules",
27 | "dev": "rollup -c rollup.config.js -w",
28 | "preinstall": "npx use-yarn",
29 | "lint": "eslint src/**/*.js",
30 | "lint:fix": "eslint src/**/*.js --fix",
31 | "test": "echo 'No tests, coming soon!'"
32 | },
33 | "husky": {
34 | "hooks": {
35 | "pre-push": "yarn lint"
36 | }
37 | },
38 | "devDependencies": {
39 | "@caldera-digital/rollup-config": "^1.0.3",
40 | "@caldera-digital/theme": "^0.1.8"
41 | },
42 | "peerDependencies": {
43 | "@caldera-digital/theme": "^1.0.5",
44 | "react": "16.8.6",
45 | "react-dom": "16.8.6",
46 | "styled-components": "4.2.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/nav/src/Hamburger.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { media } from '@caldera-digital/theme'
4 |
5 | const Hb1 = styled.div``
6 | const Hb2 = styled.div``
7 | const Hb3 = styled.div``
8 |
9 | const HamburgerWrapper = styled.div`
10 | box-sizing: initial;
11 | left: 0;
12 | top: 0;
13 | margin: 0;
14 | width: 18px;
15 | height: 18px;
16 | padding: 3px;
17 | text-align: center;
18 | cursor: pointer;
19 | transition: opacity 250ms ease;
20 | display: none;
21 |
22 | ${media.forSmallOnly`
23 | display: block;
24 | `};
25 |
26 | > div {
27 | position: relative;
28 | background-color: ${props => props.hamburgerColor || props.theme.white};
29 | width: 20px;
30 | height: 3px;
31 | border-width: 1px 0;
32 | margin: 0 auto 3px;
33 | padding: 0;
34 | border-radius: 1px;
35 | font-size: 1px;
36 | transition: all 200ms ease;
37 | transform-origin: 0 0;
38 |
39 | &:last-child {
40 | margin: 0;
41 | }
42 | }
43 |
44 | &[open] {
45 | ${Hb1} {
46 | transform: translate(4px, -1px) rotate(45deg);
47 | }
48 |
49 | ${Hb2} {
50 | opacity: 0;
51 | }
52 |
53 | ${Hb3} {
54 | transform: translate(2px, 1px) rotate(-45deg);
55 | }
56 | }
57 | `
58 |
59 | export const Hamburger = props => (
60 |
61 |
62 |
63 |
64 |
65 | )
66 |
--------------------------------------------------------------------------------
/packages/theme/src/theme.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const ThemeContext = React.createContext()
4 |
5 | export const DEFAULT_THEME = {
6 | defaultFont: '"Helvetica Neue", Arial, "Noto Sans"',
7 | defaultFontColor: '#090728',
8 | defaultFontSize: '18px',
9 | defaultHeaderColor: '#333333',
10 | defaultHeaderFont: '"Helvetica Neue", Arial, "Noto Sans"',
11 | defaultInputBackgroundColor: '#f5f5f5',
12 | defaultMobileFontSize: '16px',
13 | defaultTransition: 'all 0.2s linear',
14 | defaultParagraphLineHeight: '1.15',
15 | desktopHeaderHeight: '80px',
16 | disabledColor: '#888888',
17 | errorColor: '#e44100',
18 | focusColor: '#4c9aff',
19 | grayText: '#959595',
20 | linkColor: '#2f74ce',
21 | maxContainerWidth: '1140px',
22 | mobileHeaderHeight: '60px',
23 | negativeColor: '#cc432a',
24 | positiveColor: '#52b74d',
25 | primaryColor: '#010628',
26 | white: '#ffffff',
27 | }
28 |
29 | export const CalderaDigitalThemeProvider = ({ theme = {}, children }) => (
30 |
31 | {children}
32 |
33 | )
34 |
35 | export const CalderaDigitalThemeConsumer = ThemeContext.Consumer
36 |
37 | export const getTheme = Component =>
38 | class GetTheme extends React.Component {
39 | render() {
40 | return (
41 |
42 | {theme => }
43 |
44 | )
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/guess-the-throne/dark-blue-blob1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/caldera-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/gamebyrd/red-blob3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/pride-of-the-meadows/green-blob4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/guess-the-throne/dark-blue-blob3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/guess-the-throne/dark-blue-blob4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/its-a-date/teal-blob3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/its-a-date/teal-blob1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/pride-of-the-meadows/green-blob3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/guess-the-throne/dark-blue-blob2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/gamebyrd/red-blob1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/pride-of-the-meadows/green-blob1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/pride-of-the-meadows/green-blob2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
15 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // ESLint will yell at you until this is fixed
2 | // https://github.com/facebook/create-react-app/issues/7529
3 |
4 | module.exports = {
5 | parser: '@typescript-eslint/parser',
6 | extends: [
7 | 'node',
8 | 'plugin:import/errors',
9 | 'react-app',
10 | 'plugin:@typescript-eslint/recommended',
11 | 'plugin:prettier/recommended',
12 | ],
13 | plugins: ['jest', '@typescript-eslint/eslint-plugin', 'react'],
14 | rules: {
15 | 'arrow-body-style': ['off'],
16 | 'comma-dangle': ['off'],
17 | 'class-methods-use-this': ['off'],
18 | 'no-invalid-this': ['off'],
19 | 'import/no-named-as-default': ['off'],
20 | quotes: [2, 'single'],
21 | semi: ['off'],
22 | 'no-console': ['off'],
23 | 'import/no-nodejs-modules': ['off'],
24 | 'import/prefer-default-export': ['off'],
25 | 'import/no-namespace': ['off'],
26 | 'import/noextraneous-dependencies': ['off'],
27 | 'import/no-unresolved': ['off'],
28 | 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
29 | 'no-sync': ['off', { allowRootLevel: true }],
30 | 'jest/no-disabled-tests': ['off'],
31 | '@typescript-eslint/no-explicit-any': ['off'],
32 | '@typescript-eslint/indent': ['off'],
33 | '@typescript-eslint/ban-ts-ignore': ['off'],
34 | '@typescript-eslint/member-delimiter-style': ['off'],
35 | '@typescript-eslint/camelcase': ['off'],
36 | '@typescript-eslint/explicit-function-return-type': ['off'],
37 | },
38 | globals: {
39 | jest: true,
40 | },
41 | }
42 |
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/core",
3 | "version": "1.0.1",
4 | "description": "Utility functions and small components used in Caldera apps",
5 | "keywords": [
6 | "caldera digital"
7 | ],
8 | "homepage": "https://github.com/caldera-digital/platform#readme",
9 | "bugs": {
10 | "url": "https://github.com/caldera-digital/platform/issues"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/caldera-digital/platform.git"
15 | },
16 | "publishConfig": {
17 | "access": "public"
18 | },
19 | "license": "MIT",
20 | "main": "dist/index.js",
21 | "module": "dist/index.module.js",
22 | "scripts": {
23 | "build": "rollup -c rollup.config.js",
24 | "clean": "run-p clean:*",
25 | "clean:build": "rimraf dist",
26 | "clean:node_modules": "rimraf node_modules",
27 | "dev": "rollup -c rollup.config.js -w",
28 | "preinstall": "npx use-yarn",
29 | "lint": "eslint src/**/*.js",
30 | "lint:fix": "eslint src/**/*.js --fix",
31 | "test": "echo 'No tests, coming soon!'"
32 | },
33 | "husky": {
34 | "hooks": {
35 | "pre-push": "yarn lint"
36 | }
37 | },
38 | "devDependencies": {
39 | "@caldera-digital/rollup-config": "^1.0.3",
40 | "@caldera-digital/theme": "^0.1.8"
41 | },
42 | "peerDependencies": {
43 | "@caldera-digital/theme": "^1.0.5",
44 | "react": "16.8.6",
45 | "react-dom": "16.8.6",
46 | "styled-components": "4.2.0"
47 | },
48 | "dependencies": {
49 | "@brainhubeu/react-carousel": "^1.10.17"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/gamebyrd/red-blob2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
15 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/its-a-date/teal-blob2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
15 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/packages/babel-preset/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/babel-preset",
3 | "version": "1.0.2",
4 | "description": "Babel preset, recommended from Caldera Digital",
5 | "keywords": [
6 | "caldera digital"
7 | ],
8 | "homepage": "https://github.com/caldera-digital/platform#readme",
9 | "bugs": {
10 | "url": "https://github.com/caldera-digital/platform/issues"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/caldera-digital/platform.git"
15 | },
16 | "license": "MIT",
17 | "author": "Marcus Wood ",
18 | "main": "src/index.js",
19 | "scripts": {
20 | "build": "echo 'N/A'",
21 | "clean": "run-p clean:*",
22 | "clean:build": "rimraf dist",
23 | "clean:node_modules": "rimraf node_modules",
24 | "dev": "echo 'N/A'",
25 | "preinstall": "npx use-yarn",
26 | "lint": "eslint src/**/*.js",
27 | "lint:fix": "yarn lint --fix",
28 | "precommit": "lint-staged",
29 | "test": "echo 'N/A'"
30 | },
31 | "dependencies": {
32 | "@babel/plugin-proposal-class-properties": "^7.0.0",
33 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
34 | "@babel/plugin-syntax-dynamic-import": "^7.0.0",
35 | "@babel/plugin-transform-runtime": "^7.0.0",
36 | "@babel/preset-env": "^7.0.0",
37 | "@babel/preset-flow": "^7.0.0",
38 | "@babel/preset-react": "^7.0.0",
39 | "@babel/runtime": "^7.0.0",
40 | "babel-plugin-dynamic-import-node": "^2.2.0",
41 | "babel-plugin-inline-react-svg": "^1.1.0",
42 | "babel-plugin-transform-react-remove-prop-types": "^0.4.21"
43 | },
44 | "publishConfig": {
45 | "access": "public"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/rollup-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/rollup-config",
3 | "version": "1.0.3",
4 | "description": "Rollup config used by Caldera Digital",
5 | "keywords": [
6 | "caldera digital"
7 | ],
8 | "homepage": "https://github.com/caldera-digital/platform#readme",
9 | "bugs": {
10 | "url": "https://github.com/caldera-digital/platform/issues"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/caldera-digital/platform.git"
15 | },
16 | "license": "MIT",
17 | "author": "Marcus Wood ",
18 | "main": "dist/index.js",
19 | "scripts": {
20 | "build": "babel src --out-dir dist/ --ignore '**/*.test.js'",
21 | "clean": "run-p clean:*",
22 | "clean:build": "rimraf dist",
23 | "clean:node_modules": "rimraf node_modules",
24 | "dev": "onchange -i 'src/**/*.js' -- yarn build",
25 | "preinstall": "npx use-yarn",
26 | "lint": "eslint src/**/*.js",
27 | "lint:fix": "yarn lint --fix",
28 | "precommit": "lint-staged",
29 | "test": "echo 'N/A'"
30 | },
31 | "lint-staged": {
32 | "linters": {
33 | "*.js": [
34 | "yarn lint:fix",
35 | "git add"
36 | ]
37 | }
38 | },
39 | "dependencies": {
40 | "@caldera-digital/babel-preset": "^1.0.2",
41 | "@svgr/rollup": "^4.2.0",
42 | "rollup": "^1.10.1",
43 | "rollup-plugin-babel": "^4.3.2",
44 | "rollup-plugin-commonjs": "^9.3.4",
45 | "rollup-plugin-json": "^4.0.0",
46 | "rollup-plugin-node-builtins": "^2.1.2",
47 | "rollup-plugin-node-resolve": "^4.2.3",
48 | "rollup-plugin-postcss": "^2.0.3"
49 | },
50 | "publishConfig": {
51 | "access": "public"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/.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 | packages/*/dist
13 | projects/*/dist
14 |
15 | packages/*/build
16 | projects/*/build
17 |
18 | # misc
19 | .DS_Store
20 | .env.local
21 | .env.development.local
22 | .env.test.local
23 | .env.production.local
24 |
25 | # Logs
26 | logs
27 | *.log
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 |
32 | # Runtime data
33 | pids
34 | *.pid
35 | *.seed
36 | *.pid.lock
37 |
38 | # Directory for instrumented libs generated by jscoverage/JSCover
39 | lib-cov
40 |
41 | # Coverage directory used by tools like istanbul
42 | coverage
43 |
44 | # nyc test coverage
45 | .nyc_output
46 |
47 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
48 | .grunt
49 |
50 | # Bower dependency directory (https://bower.io/)
51 | bower_components
52 |
53 | # node-waf configuration
54 | .lock-wscript
55 |
56 | # Compiled binary addons (http://nodejs.org/api/addons.html)
57 | build/Release
58 |
59 | # Dependency directories
60 | jspm_packages/
61 |
62 | # Typescript v1 declaration files
63 | typings/
64 |
65 | # Optional npm cache directory
66 | .npm
67 |
68 | # Optional eslint cache
69 | .eslintcache
70 |
71 | # Optional REPL history
72 | .node_repl_history
73 |
74 | # Output of 'npm pack'
75 | *.tgz
76 |
77 | # dotenv environment variables file
78 | .env
79 |
80 | # gatsby files
81 | .cache/
82 | projects/caldera-www/public
83 |
84 | # Yarn
85 | yarn-error.log
86 | .pnp/
87 | .pnp.js
88 | # Yarn Integrity file
89 | .yarn-integrity
90 |
91 | service-account-key.json
92 |
--------------------------------------------------------------------------------
/packages/rollup-config/src/index.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel'
2 | import resolve from 'rollup-plugin-node-resolve'
3 | import commonjs from 'rollup-plugin-commonjs'
4 | import json from 'rollup-plugin-json'
5 | import svgr from '@svgr/rollup'
6 | import builtins from 'rollup-plugin-node-builtins'
7 | import postcss from 'rollup-plugin-postcss'
8 | import calderaDigitalBabelPreset from '@caldera-digital/babel-preset'
9 |
10 | // const isProd = process.env.NODE_ENV === 'production'
11 |
12 | const globals = {
13 | 'styled-components': 'StyledComponents',
14 | react: 'React',
15 | 'react-dom': 'ReactDOM',
16 | // Don't package because then it will bundle into packages and we need to use the
17 | // same instance in memory for context for work.
18 | '@caldera-digital/theme': '@caldera-digital/theme',
19 | }
20 |
21 | const extensions = ['.js', '.jsx', '.ts', '.tsx']
22 |
23 | export default ({ name }, input = './src/index.js') => ({
24 | input,
25 | output: [
26 | {
27 | file: './dist/index.js',
28 | format: 'umd',
29 | name,
30 | globals,
31 | sourcemap: true,
32 | },
33 | {
34 | file: './dist/index.module.js',
35 | format: 'es',
36 | globals,
37 | sourcemap: true,
38 | },
39 | ],
40 | plugins: [
41 | postcss({
42 | extract: true,
43 | }),
44 | builtins(),
45 | resolve({ extensions }),
46 | babel({
47 | exclude: /node_modules/,
48 | extensions,
49 | presets: [calderaDigitalBabelPreset],
50 | }),
51 | commonjs({
52 | include: /node_modules/,
53 | }),
54 | json({
55 | compact: true,
56 | preferConst: true,
57 | }),
58 | svgr(),
59 | ],
60 | external: Object.keys(globals),
61 | })
62 |
--------------------------------------------------------------------------------
/packages/babel-preset/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 |
7 | ## [1.0.2](https://github.com/caldera-digital/platform/compare/@caldera-digital/babel-preset@1.0.1...@caldera-digital/babel-preset@1.0.2) (2019-05-31)
8 |
9 |
10 | ### :sparkles: Features
11 |
12 | * publish repos so ci works ([273715a](https://github.com/caldera-digital/platform/commit/273715a))
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## [1.0.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/babel-preset@0.1.1...@caldera-digital/babel-preset@1.0.1) (2019-05-05)
20 |
21 |
22 | ### :sparkles: Features
23 |
24 | * add container and 1.0 bump for all ([d9df7a2](https://github.com/caldera-digital/platform/commit/d9df7a2))
25 |
26 |
27 |
28 |
29 |
30 |
31 | ## 0.1.1 (2019-05-03)
32 |
33 |
34 | ### :sparkles: Features
35 |
36 | * add babel config and rollup config and add nav ([8d63d90](https://github.com/caldera-digital/platform/commit/8d63d90))
37 | * add cosmos, fix configs, fix nav, add theme ([1fc5896](https://github.com/caldera-digital/platform/commit/1fc5896))
38 | * dev, build, clean, and bootstrap all working ([fde0074](https://github.com/caldera-digital/platform/commit/fde0074))
39 | * fix babel preset, bootstrap working, rollup config ([bfcd694](https://github.com/caldera-digital/platform/commit/bfcd694))
40 |
41 |
42 | ### :ticket: Chores
43 |
44 | * add readme and sort package jsons ([418f93b](https://github.com/caldera-digital/platform/commit/418f93b))
45 | * fix linter, start on travis ([22dcc54](https://github.com/caldera-digital/platform/commit/22dcc54))
46 |
--------------------------------------------------------------------------------
/packages/theme/src/GlobalStyle.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from 'styled-components'
2 | import { media } from './media'
3 |
4 | /**
5 | * Some of this pulled from Bootstrap's source:
6 | * https://github.com/twbs/bootstrap/blob/master/dist/css/bootstrap.css
7 | */
8 | export const GlobalStyle = createGlobalStyle`
9 | *,
10 | *::before,
11 | *::after {
12 | box-sizing: border-box;
13 | }
14 |
15 | html {
16 | font-size: ${props => props.theme.defaultFontSize};
17 |
18 | ${media.forSmallOnly`
19 | font-size: ${props => props.theme.defaultMobileFontSize};
20 | `}
21 | }
22 |
23 | body {
24 | font-family: ${props => props.theme.defaultFont};
25 | color: ${props => props.theme.defaultFontColor};
26 | background-color: ${props => props.theme.bodyBackgroundColor};
27 |
28 | h1, h2, h3, h4, h5, h6 {
29 | margin-top: 0;
30 | margin-bottom: 0.5rem;
31 | color: ${props => props.theme.defaultHeaderColor};
32 | font-family: ${props => props.theme.defaultHeaderFont};
33 | font-weight: 400;
34 | }
35 |
36 | h1 {
37 | font-size: 1.7rem;
38 | }
39 |
40 | h2 {
41 | font-size: 1.4rem;
42 | }
43 |
44 | hr {
45 | box-sizing: content-box;
46 | height: 0;
47 | overflow: visible;
48 | }
49 |
50 | p {
51 | margin-top: 0;
52 | margin-bottom: 1rem;
53 | line-height: ${props => props.theme.defaultParagraphLineHeight};
54 | }
55 |
56 | a {
57 | color: ${props => props.theme.linkColor};
58 | text-decoration: none;
59 |
60 | &:visited {
61 | color: ${props => props.theme.linkColor};
62 | }
63 | }
64 |
65 | ol ol,
66 | ul ul,
67 | ol ul,
68 | ul ol {
69 | margin-bottom: 0;
70 | }
71 | }
72 | `
73 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/blue-blob2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/ecommerce-stripe-client",
3 | "version": "0.2.8",
4 | "publishConfig": {
5 | "access": "public"
6 | },
7 | "dependencies": {
8 | "@caldera-digital/ecommerce-stripe-shared": "^0.2.4",
9 | "@caldera-digital/nav": "^1.0.10",
10 | "@caldera-digital/theme": "^1.0.6",
11 | "antd": "^3.22.2",
12 | "customize-cra": "^0.5.0",
13 | "firebase": "^6.4.2",
14 | "firebaseui": "^4.1.0",
15 | "formik": "^1.5.8",
16 | "lodash": "^4.17.15",
17 | "normalize.css": "^8.0.1",
18 | "react": "16.8.6",
19 | "react-app-rewired": "^2.1.3",
20 | "react-dom": "16.8.6",
21 | "react-firebase-hooks": "^2.1.0",
22 | "react-firebaseui": "^4.0.0",
23 | "react-router-dom": "^5.0.1",
24 | "react-scripts": "^3.1.1",
25 | "react-stripe-elements": "^5.0.0",
26 | "recompose": "^0.30.0",
27 | "styled-components": "4.2.0",
28 | "yup": "^0.27.0"
29 | },
30 | "scripts": {
31 | "dev": "SKIP_PREFLIGHT_CHECK=true react-app-rewired start",
32 | "build": "SKIP_PREFLIGHT_CHECK=true react-app-rewired build",
33 | "test": "echo 'No tests, coming soon!'",
34 | "eject": "react-scripts eject",
35 | "clean": "run-p clean:*",
36 | "clean:build": "rimraf dist",
37 | "clean:node_modules": "rimraf node_modules",
38 | "preinstall": "npx use-yarn",
39 | "lint": "eslint src/**/*.{ts,tsx,js}",
40 | "lint:fix": "eslint src/**/*.{ts,tsx,js} --fix"
41 | },
42 | "eslintConfig": {
43 | "extends": "react-app"
44 | },
45 | "browserslist": {
46 | "production": [
47 | ">0.2%",
48 | "not dead",
49 | "not op_mini all"
50 | ],
51 | "development": [
52 | "last 1 chrome version",
53 | "last 1 firefox version",
54 | "last 1 safari version"
55 | ]
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Blob.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { jiggle } from '../style/utils'
3 | import { media } from '@caldera-digital/theme'
4 | import { css } from 'styled-components'
5 |
6 | export const COMMON_BLOB_STYLES = css`
7 | svg.blob {
8 | position: absolute;
9 | z-index: -1;
10 | animation: 15s ${jiggle} infinite;
11 |
12 | &.topRight {
13 | top: -10%;
14 | right: -30%;
15 |
16 | ${media.forSmallOnly`
17 | top: 0;
18 | right: -10%;
19 | `}
20 | }
21 |
22 | &.topLeft {
23 | top: -10%;
24 | left: -50%;
25 |
26 | ${media.forSmallOnly`
27 | top: 0;
28 | left: -10%;
29 | `}
30 | }
31 |
32 | &.bottomLeft {
33 | left: -35%;
34 | bottom: -15%;
35 |
36 | ${media.forSmallOnly`
37 | left: -20%;
38 | bottom: -10%;
39 | `}
40 | }
41 |
42 | &.blob-small {
43 | width: 50%;
44 |
45 | ${media.forSmallOnly`
46 | width: 120%;
47 | `}
48 | }
49 |
50 | &.blob-medium {
51 | width: 70%;
52 |
53 | ${media.forSmallOnly`
54 | width: 120%;
55 | `}
56 | }
57 |
58 | &.blob-smedium {
59 | }
60 | &.blob-large {
61 | }
62 | &.blob-extra-large {
63 | width: 130%;
64 | }
65 |
66 | &.hideOnSmallMedium {
67 | ${media.forSmallMediumOnly`
68 | display: none;
69 | `}
70 | }
71 | }
72 | `
73 |
74 | export const BlobHandler = ({ blobs = [] }) => {
75 | return (
76 | <>
77 | {blobs.map(({ blob: Blob, position, size, hideOnSmallMedium }, i) => (
78 |
84 | ))}
85 | >
86 | )
87 | }
88 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/pages/CartPage/CartPage.tsx:
--------------------------------------------------------------------------------
1 | import { Icon, message } from 'antd'
2 | import React, { FC } from 'react'
3 | import { Elements } from 'react-stripe-elements'
4 |
5 | import { PageWrapper, PrivateRouteReturnComponentProps } from '../../components'
6 | import { ProductList } from '../../components/productList'
7 | import firebase from '../../config/firebase'
8 | import { ProductShort } from '../../types'
9 | import { CheckoutForm } from './CheckoutForm'
10 |
11 | const db = firebase.firestore()
12 |
13 | type P = PrivateRouteReturnComponentProps
14 |
15 | export const CartPage: FC = ({ user }) => {
16 | const userRef = db.collection('users').doc(user.userId)
17 |
18 | return (
19 |
20 |
28 |
Cart
29 |
30 | {/* Initializes form */}
31 |
32 |
33 |
34 |
35 | [
39 | {
43 | const cart = user.cart.filter(
44 | (p: ProductShort) => p.id !== product.id,
45 | )
46 |
47 | try {
48 | await userRef.update({ cart })
49 | message.success('Item removed from cart!')
50 | } catch (error) {
51 | message.error('Remove from cart error: Please try again.')
52 | }
53 | }}
54 | />,
55 | ]}
56 | />
57 |
58 | )
59 | }
60 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Layout.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import {
3 | CalderaDigitalThemeProvider,
4 | CalderaDigitalThemeConsumer,
5 | GlobalStyle,
6 | media,
7 | } from '@caldera-digital/theme'
8 | import styled, { ThemeProvider } from 'styled-components'
9 | import { theme as customTheme } from '../style'
10 | import { NavBar, Footer } from '../components'
11 |
12 | import 'normalize.css'
13 |
14 | const MainContentContainer = styled.main`
15 | margin-bottom: 6rem;
16 |
17 | ${media.forSmallOnly`
18 | margin-top: ${props => props.theme.mobileHeaderHeight};
19 | `}
20 | `
21 |
22 | export class Layout extends Component {
23 | componentDidCatch(error, errorInfo) {
24 | const { Sentry } = window
25 | console.log('erfe', error)
26 | Sentry.configureScope(scope => {
27 | Object.keys(errorInfo).forEach(key => {
28 | scope.setExtra(key, errorInfo[key])
29 | })
30 | })
31 | Sentry.captureException(error)
32 | }
33 |
34 | render() {
35 | // const rootPath = `${__PATH_PREFIX__}/`
36 | // eslint-disable-next-line no-undef
37 |
38 | const {
39 | location,
40 | children,
41 | showFooterCTA = true,
42 | className = '',
43 | } = this.props
44 |
45 | return (
46 |
47 |
48 | {theme => (
49 |
50 | <>
51 |
52 |
53 |
54 | {children}
55 |
56 |
57 | >
58 |
59 | )}
60 |
61 |
62 | )
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Gamebyrd
28 |
29 |
30 |
31 |
32 | You need to enable JavaScript to run this app.
33 |
34 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Homepage/Welcome.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BlobSection } from '../Section'
3 | import styled from 'styled-components'
4 | import { media } from '@caldera-digital/theme'
5 |
6 | import Blob from '../../assets/svgs/blue-blob2.svg'
7 |
8 | const WelcomeTextContainer = styled.div`
9 | flex: 1;
10 |
11 | h2 {
12 | font-weight: bold;
13 | font-size: 3rem;
14 | margin-bottom: 1.5rem;
15 | }
16 |
17 | ${media.forSmallMediumOnly`
18 | h2 {
19 | font-size: 2rem;
20 | margin-bottom: 1.25rem;
21 | }
22 | `}
23 | `
24 |
25 | const BreakoutSection = styled.div`
26 | border-left: 6px solid ${props => props.theme.secondaryColor};
27 | padding-left: 1.5rem;
28 | margin-left: 1rem;
29 |
30 | > p {
31 | &:first-child {
32 | font-size: 1.8rem;
33 | }
34 |
35 | &:last-child {
36 | color: ${props => props.theme.grayText};
37 | }
38 | }
39 |
40 | ${media.forSmallMediumOnly`
41 | padding-left: 1.5rem;
42 | margin-left: 1rem;
43 |
44 | > p {
45 | &:first-child {
46 | font-size: 1.4rem;
47 | }
48 |
49 | &:last-child {
50 | color: ${props => props.theme.grayText};
51 | }
52 | }
53 | `}
54 | `
55 |
56 | export const Welcome = () => {
57 | return (
58 |
59 |
60 |
61 | We use innovative technology to bring your vision, brand, and identity
62 | to life.
63 |
64 |
65 |
66 | We are graphic artists and designers, expert coders, and published
67 | writers. Caldera is your one-stop-shop. We take pride in working
68 | with the best and latest technology out there - and in turn, bring
69 | only the best to your business.
70 |
71 |
72 |
73 |
74 | )
75 | }
76 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-server/src/onCreateUser.ts:
--------------------------------------------------------------------------------
1 | import * as admin from 'firebase-admin'
2 | import { auth } from 'firebase-functions'
3 | import { UserRecord } from 'firebase-functions/lib/providers/auth'
4 | import { getOr } from 'lodash/fp'
5 |
6 | import { db } from './utils/store'
7 |
8 | const splitName = (fullName: string | undefined): Array => {
9 | if (!fullName) return ['', '']
10 |
11 | const splitName = fullName.split(/(\s+)/)
12 | const firstName = splitName[0] ? splitName[0] : ''
13 | const lastName = splitName[2] ? splitName[2] : ''
14 |
15 | return [firstName, lastName]
16 | }
17 |
18 | const createProfile = async ({ uid }: UserRecord) => {
19 | const usersRef = db.collection('users').doc(uid)
20 |
21 | try {
22 | // Need to make another round trip so we can get the user's name and other information
23 | const authedUserRecord = await admin.auth().getUser(uid)
24 | const [firstName, lastName] = splitName(authedUserRecord.displayName)
25 |
26 | await usersRef.set({
27 | cart: [],
28 | purchases: [],
29 | stripeCustomerID: '',
30 | stripeCharges: [],
31 | userId: authedUserRecord.uid,
32 | joined: admin.firestore.FieldValue.serverTimestamp(),
33 | email: authedUserRecord.email,
34 | displayName: getOr('', 'displayName', authedUserRecord),
35 | firstName,
36 | lastName,
37 | // Potentially come in depending on sign in provider
38 | photoURL: getOr('', 'photoURL', authedUserRecord),
39 | phoneNumber: getOr('', 'phoneNumber', authedUserRecord),
40 | })
41 | } catch (error) {
42 | console.error('Add User to Firestore Failed:', error)
43 | }
44 | }
45 |
46 | // This is called when the user is authed NOT when all of the user's info is stored in the Auth side of Firebase
47 | // https://stackoverflow.com/questions/43223896/user-displayname-is-undefined-in-oncreate-trigger-for-email-sign-up-method
48 | export const createUser = auth.user().onCreate(createProfile)
49 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/pages/ThankYou/ThankYou.tsx:
--------------------------------------------------------------------------------
1 | import { round, sortBy } from 'lodash'
2 | import React, { FC } from 'react'
3 | import { RouteComponentProps } from 'react-router-dom'
4 |
5 | import { PageWrapper, PrivateRouteReturnComponentProps } from '../../components'
6 | import { ProductList } from '../../components/productList'
7 | import { getPurchaseByFirebaseID } from '../../utils/utilityService'
8 |
9 | type P = PrivateRouteReturnComponentProps & RouteComponentProps
10 |
11 | // Need test! Add a helper like this to the Stripe elements library?
12 | const prettyStripeAmount = (amount: number) => {
13 | return round(amount / 100, 2).toLocaleString('en-US', {
14 | style: 'currency',
15 | currency: 'USD',
16 | })
17 | }
18 |
19 | export const ThankYouPage: FC = ({
20 | user: { purchases, firstName, stripeCharges, stripeCustomerID },
21 |
22 | match: {
23 | // @ts-ignore
24 | params: { orderID },
25 | },
26 | }) => {
27 | const purchase = getPurchaseByFirebaseID(purchases, orderID)
28 | // Make sure it's sorted by most recent charge
29 | const [mostRecentCharge, ...previousCharges] = sortBy(
30 | stripeCharges,
31 | 'created',
32 | ).reverse()
33 |
34 | return (
35 |
36 | Thank You, {firstName}!
37 | Your order number is: {mostRecentCharge.id}
38 | Customer number: {stripeCustomerID}
39 | Total amount charged: {prettyStripeAmount(mostRecentCharge.amount)}
40 |
41 | Your Items
42 |
43 |
44 | {previousCharges && previousCharges.length > 0 && (
45 | <>
46 | Charges History
47 | {previousCharges.map(charge => (
48 |
49 | {new Date(charge.created * 1000).toLocaleDateString('en-US')}{' '}
50 | {charge.id} {prettyStripeAmount(charge.amount)}
51 |
52 | ))}
53 | >
54 | )}
55 |
56 | )
57 | }
58 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/blue-blob5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/components/productList.tsx:
--------------------------------------------------------------------------------
1 | import { Card, Col, Row } from 'antd'
2 | import { truncate } from 'lodash/fp'
3 | import React, { FC, ReactNode } from 'react'
4 | import styled from 'styled-components'
5 |
6 | import { Product, ProductShort } from '../types'
7 |
8 | type ProductListProps = {
9 | products: Product[] | ProductShort[]
10 | renderActions?: (product: Product | ProductShort) => ReactNode[]
11 | emptyText?: string
12 | }
13 | type ProductListItemProps = {
14 | product: Product | ProductShort
15 | renderActions?: (product: Product | ProductShort) => ReactNode[]
16 | }
17 |
18 | const StyledImage = styled.img`
19 | width: 100%;
20 | height: 250px;
21 | object-fit: cover;
22 | `
23 |
24 | export const ProductListItem: FC = ({
25 | product,
26 | renderActions,
27 | }) => {
28 | return (
29 |
30 | }
33 | style={{ marginBottom: '1rem' }}
34 | actions={renderActions ? renderActions(product) : []}
35 | >
36 |
40 |
41 | Price: ${product.price}
42 |
43 |
44 | {truncate({ length: 250, separator: ' ' }, product.description)}
45 |
46 |
47 | }
48 | style={{ minHeight: '150px' }}
49 | />
50 |
51 |
52 | )
53 | }
54 |
55 | export const ProductList: FC = ({
56 | products = [],
57 | renderActions,
58 | emptyText = 'No products to display.',
59 | }) => {
60 | if (products.length === 0) return {emptyText}
61 |
62 | return (
63 |
64 | {products.map(product => (
65 |
70 | ))}
71 |
72 | )
73 | }
74 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
--------------------------------------------------------------------------------
/packages/rollup-config/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 |
7 | ## [1.0.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/rollup-config@1.0.2...@caldera-digital/rollup-config@1.0.3) (2019-08-29)
8 |
9 |
10 | ### :sparkles: Features
11 |
12 | * home page and mobile tweaks ([b5b820e](https://github.com/caldera-digital/platform/commit/b5b820e))
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## [1.0.2](https://github.com/caldera-digital/platform/compare/@caldera-digital/rollup-config@1.0.1...@caldera-digital/rollup-config@1.0.2) (2019-05-31)
20 |
21 |
22 | ### :bug: Bug Fixes
23 |
24 | * bump versions to right level ([ab845a8](https://github.com/caldera-digital/platform/commit/ab845a8))
25 |
26 |
27 | ### :sparkles: Features
28 |
29 | * publish repos so ci works ([273715a](https://github.com/caldera-digital/platform/commit/273715a))
30 |
31 |
32 |
33 |
34 |
35 |
36 | ## [1.0.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/rollup-config@0.1.1...@caldera-digital/rollup-config@1.0.1) (2019-05-05)
37 |
38 |
39 | ### :sparkles: Features
40 |
41 | * add container and 1.0 bump for all ([d9df7a2](https://github.com/caldera-digital/platform/commit/d9df7a2))
42 |
43 |
44 |
45 |
46 |
47 |
48 | ## 0.1.1 (2019-05-03)
49 |
50 |
51 | ### :sparkles: Features
52 |
53 | * add babel config and rollup config and add nav ([8d63d90](https://github.com/caldera-digital/platform/commit/8d63d90))
54 | * add cosmos, fix configs, fix nav, add theme ([1fc5896](https://github.com/caldera-digital/platform/commit/1fc5896))
55 | * dev, build, clean, and bootstrap all working ([fde0074](https://github.com/caldera-digital/platform/commit/fde0074))
56 | * fix babel preset, bootstrap working, rollup config ([bfcd694](https://github.com/caldera-digital/platform/commit/bfcd694))
57 |
58 |
59 | ### :ticket: Chores
60 |
61 | * add readme and sort package jsons ([418f93b](https://github.com/caldera-digital/platform/commit/418f93b))
62 | * fix linter errors ([e8f1c53](https://github.com/caldera-digital/platform/commit/e8f1c53))
63 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/components/privateRoute.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useContext } from 'react'
2 | import { useDocumentData } from 'react-firebase-hooks/firestore'
3 | import { Redirect, Route, RouteProps } from 'react-router-dom'
4 |
5 | import firebase from '../config/firebase'
6 | import { AuthContext } from '../context/AuthContext'
7 | import { User } from '../types'
8 | import { Error } from './error'
9 | import { Loading } from './loading'
10 |
11 | const db = firebase.firestore()
12 |
13 | export type PrivateRouteReturnComponentProps = RouteProps & {
14 | user: User
15 | }
16 |
17 | type PrivateRouteProps = {
18 | component: FC
19 | }
20 | type P = PrivateRouteProps & RouteProps | any
21 |
22 | /**
23 | * Why here?
24 | *
25 | * Because the cloud functions take time to heat up on a cold start and putting it in the auth context could result in a user
26 | * being redirected and kicked back to login because the document in the DB isn't ready to be queried
27 | */
28 | const RenderAuthedComponent: FC = ({
29 | component: Component,
30 | user: authedUserRecord,
31 | ...rest
32 | }) => {
33 | const [user, loading, error] = useDocumentData(
34 | db.collection('users').doc(authedUserRecord.uid),
35 | )
36 | if (loading || !user) return
37 | if (error) return
38 |
39 | return
40 | }
41 |
42 | export const PrivateRoute: FC = ({
43 | component: requestedComponent,
44 | ...rest
45 | }: P) => {
46 | const { isAuthed, user, loading } = useContext(AuthContext)
47 |
48 | // Firebase auth is async!
49 | if (loading) return
50 |
51 | return (
52 |
56 | isAuthed && user ? (
57 |
62 | ) : (
63 |
69 | )
70 | }
71 | />
72 | )
73 | }
74 |
--------------------------------------------------------------------------------
/packages/babel-preset/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 | // Mostly taken from https://github.com/phenomic/phenomic/blob/master/packages/babel-preset/src/index.js
3 |
4 | // most of this has been inspired by
5 | // https://github.com/facebook/create-react-app/tree/master/packages/babel-preset-react-app
6 |
7 | module.exports = ({ modules } = { modules: false }) => ({
8 | presets: [
9 | [
10 | require('@babel/preset-env'),
11 | {
12 | modules,
13 | },
14 | ],
15 | [
16 | require('@babel/preset-react'),
17 | {
18 | // Will use the native built-in instead of trying to polyfill
19 | // behavior for any plugins that require one.
20 | useBuiltIns: true,
21 | },
22 | ],
23 | ],
24 | plugins: [
25 | // Enable loose mode to use assignment instead of defineProperty
26 | // See discussion in https://github.com/facebook/create-react-app/issues/4263
27 | [
28 | require('@babel/plugin-proposal-class-properties'),
29 | {
30 | loose: true,
31 | },
32 | ],
33 | // The following two plugins use Object.assign directly, instead of Babel's
34 | // extends helper. Note that this assumes `Object.assign` is available.
35 | // { ...todo, completed: true }
36 | [
37 | require('@babel/plugin-proposal-object-rest-spread'),
38 | {
39 | useBuiltIns: true,
40 | },
41 | ],
42 | // Polyfills the runtime needed for async/await, generators, and friends
43 | // https://babeljs.io/docs/en/babel-plugin-transform-runtime
44 | [
45 | require('@babel/plugin-transform-runtime'),
46 | {
47 | corejs: false,
48 | helpers: false,
49 | regenerator: true,
50 | useESModules: true,
51 | },
52 | ],
53 | ...(process.env.NODE_ENV === 'production'
54 | ? [
55 | [
56 | // Remove PropTypes from production build
57 | require('babel-plugin-transform-react-remove-prop-types'),
58 | {
59 | removeImport: true,
60 | },
61 | ],
62 | ]
63 | : []),
64 | // Adds syntax support for import()
65 | require('@babel/plugin-syntax-dynamic-import'),
66 | require('babel-plugin-inline-react-svg'),
67 | ],
68 | })
69 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Homepage/WhoWeveWorkedWith.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Section } from '../Section'
3 | import styled from 'styled-components'
4 | import { media } from '@caldera-digital/theme'
5 |
6 | import CAMLogo from '../../assets/rawSvgs/clients/cam-logo.svg'
7 | import POTMLogo from '../../assets/rawSvgs/clients/potm-logo.svg'
8 | import TenOaksLogo from '../../assets/rawSvgs/clients/ten-oaks-logo.svg'
9 | import ItsADateLogo from '../../assets/images/its-a-date-logo.png'
10 |
11 | const CLIENTS = [
12 | {
13 | name: 'Ten Oaks Flooring',
14 | to: 'https://www.tenoaksflooring.com/',
15 | image: TenOaksLogo,
16 | },
17 | {
18 | name: 'CAM',
19 | to: 'https://www.camaerospace.com/',
20 | image: CAMLogo,
21 | },
22 | {
23 | name: 'Pride of the Meadows',
24 | to: 'https://www.prideofthemeadows.com/',
25 | image: POTMLogo,
26 | },
27 | {
28 | // eslint-disable-next-line quotes
29 | name: "It's a Date",
30 | to: 'https://www.itsadate.app/',
31 | image: ItsADateLogo,
32 | },
33 | ]
34 |
35 | const LogosWrapper = styled.div`
36 | display: flex;
37 | justify-content: center;
38 | align-items: center;
39 |
40 | ${media.forSmallMediumOnly`
41 | flex-wrap: wrap;
42 | `}
43 | `
44 |
45 | const FlexibleImage = styled.a`
46 | flex: 1;
47 | padding: 1rem;
48 | height: 150px;
49 |
50 | > img {
51 | width: 100%;
52 | height: 100%;
53 | object-fit: contain;
54 | }
55 |
56 | ${media.forSmallMediumOnly`
57 | flex: auto;
58 | height: 175px;
59 | width: 50%;
60 | padding: 2rem 1rem;
61 | `}
62 |
63 | ${media.forSmallOnly`
64 | padding: 2rem 1rem;
65 |
66 | &:nth-child(odd) {
67 | padding-left: 0;
68 | }
69 | &:nth-child(even) {
70 | padding-right: 0;
71 | }
72 | `}
73 | `
74 |
75 | export const WhoWeveWorkedWith = () => {
76 | return (
77 |
78 |
79 | {CLIENTS.map(client => (
80 |
86 |
87 |
88 | ))}
89 |
90 |
91 | )
92 | }
93 |
--------------------------------------------------------------------------------
/projects/caldera-www/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@caldera-digital/caldera-www",
3 | "description": "Website for Caldera.",
4 | "version": "0.2.8",
5 | "author": "Marcus Wood ",
6 | "bugs": {
7 | "url": "https://github.com/gatsbyjs/gatsby/issues"
8 | },
9 | "publishConfig": {
10 | "access": "public"
11 | },
12 | "dependencies": {
13 | "@brainhubeu/react-carousel": "^1.10.17",
14 | "@caldera-digital/core": "^1.0.1",
15 | "@caldera-digital/nav": "^1.0.10",
16 | "@caldera-digital/theme": "^1.0.6",
17 | "babel-plugin-styled-components": "^1.10.0",
18 | "gatsby": "2.13.41",
19 | "gatsby-image": "^2.1.0",
20 | "gatsby-plugin-canonical-urls": "^2.1.2",
21 | "gatsby-plugin-disqus": "^1.1.2",
22 | "gatsby-plugin-feed": "^2.2.0",
23 | "gatsby-plugin-google-analytics": "^2.0.20",
24 | "gatsby-plugin-mailchimp": "^5.1.2",
25 | "gatsby-plugin-manifest": "^2.2.4",
26 | "gatsby-plugin-netlify": "^2.0.17",
27 | "gatsby-plugin-offline": "^2.1.1",
28 | "gatsby-plugin-polyfill-io": "^1.1.0",
29 | "gatsby-plugin-react-helmet": "^3.0.12",
30 | "gatsby-plugin-react-svg": "^2.1.1",
31 | "gatsby-plugin-sentry": "^1.0.1",
32 | "gatsby-plugin-sitemap": "^2.1.0",
33 | "gatsby-plugin-styled-components": "^3.0.7",
34 | "gatsby-remark-smartypants": "^2.0.9",
35 | "gatsby-source-filesystem": "^2.0.36",
36 | "gatsby-transformer-remark": "^2.3.12",
37 | "gatsby-transformer-sharp": "^2.2.4",
38 | "gatsby-plugin-sharp": "^2.2.9",
39 | "normalize.css": "^8.0.1",
40 | "react": "^16.8.6",
41 | "react-dom": "^16.8.6",
42 | "react-helmet": "^5.2.1",
43 | "react-medium-image-zoom": "^3.1.1",
44 | "react-typography": "^0.16.19",
45 | "styled-components": "^4.2.0"
46 | },
47 | "homepage": "https://github.com/gatsbyjs/gatsby-starter-blog#readme",
48 | "keywords": [
49 | "gatsby"
50 | ],
51 | "license": "MIT",
52 | "main": "n/a",
53 | "repository": {
54 | "type": "git",
55 | "url": "git+https://github.com/gatsbyjs/gatsby-starter-blog.git"
56 | },
57 | "scripts": {
58 | "build": "gatsby build",
59 | "clean": "run-p clean:*",
60 | "clean:build": "rimraf dist",
61 | "clean:node_modules": "rimraf node_modules",
62 | "dev": "gatsby develop",
63 | "preinstall": "npx use-yarn",
64 | "lint": "eslint src/**/*.js",
65 | "lint:fix": "eslint src/**/*.js --fix",
66 | "test": "echo 'No tests, coming soon!'"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/pages/HomePage/HomePage.tsx:
--------------------------------------------------------------------------------
1 | import { Icon, message } from 'antd'
2 | import React, { FC } from 'react'
3 | import { useCollectionData } from 'react-firebase-hooks/firestore'
4 |
5 | import {
6 | Error,
7 | Loading,
8 | PageWrapper,
9 | PrivateRouteReturnComponentProps,
10 | } from '../../components'
11 | import { ProductList } from '../../components/productList'
12 | import firebase from '../../config/firebase'
13 | import { Product, ProductShort } from '../../types'
14 | import { createShortProduct } from '../../utils/utilityService'
15 |
16 | const db = firebase.firestore()
17 |
18 | type P = PrivateRouteReturnComponentProps
19 |
20 | export const HomePage: FC = ({ user }) => {
21 | const [values, loading, error] = useCollectionData(
22 | // Only showing 30 because this is a POC and infinite scroll is high LOE
23 | db.collection('products').limit(30),
24 | )
25 | const userRef = db.collection('users').doc(user.userId)
26 | if (loading) return
27 | if (error || !values) return
28 |
29 | return (
30 |
31 | Products
32 |
33 | {
36 | const isProductAlreadyAddedToCart: boolean =
37 | user.cart.length > 0
38 | ? !!user.cart.find(
39 | (productShort: ProductShort) =>
40 | productShort.id === product.id,
41 | )
42 | : false
43 |
44 | return [
45 | {
51 | if (isProductAlreadyAddedToCart) {
52 | return message.warning(
53 | 'You can only add one of each product to your cart.',
54 | )
55 | }
56 |
57 | const cart = [...user.cart, createShortProduct(product)]
58 |
59 | try {
60 | await userRef.update({ cart })
61 | message.success('Add to cart success!')
62 | } catch (error) {
63 | message.error('Add to cart error: Please try again.')
64 | }
65 | }}
66 | />,
67 | ]
68 | }}
69 | />
70 |
71 | )
72 | }
73 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/web.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled, { css } from 'styled-components'
3 | import { media } from '@caldera-digital/theme'
4 | import { Loading } from '@caldera-digital/core'
5 | import { Link } from 'gatsby'
6 |
7 | const ButtonStyles = css`
8 | cursor: pointer;
9 | position: relative;
10 | background-color: ${props => props.theme.secondaryColor};
11 | border: none;
12 | border-radius: 40px;
13 | color: ${props => props.theme.white};
14 | font-family: ${props => props.theme.headerFont};
15 | font-size: 1.2rem;
16 | padding: 1rem 2rem;
17 | text-transform: uppercase;
18 | letter-spacing: 0.3rem;
19 | transition: ${props => props.theme.defaultTransition};
20 | display: flex;
21 | justify-content: center;
22 | align-items: center;
23 | color: ${props => props.theme.white};
24 | min-width: 240px;
25 | min-height: 48px;
26 |
27 | &:hover,
28 | &:focus {
29 | background-color: ${props => props.theme.hoveredSecondaryColor};
30 | color: ${props => props.theme.white};
31 | }
32 |
33 | &:active {
34 | background-color: ${props => props.theme.pressedSecondaryColor};
35 | color: ${props => props.theme.white};
36 | }
37 |
38 | &:visited {
39 | background-color: ${props => props.theme.secondaryColor};
40 | color: ${props => props.theme.white};
41 | }
42 |
43 | ${({ size }) => {
44 | if (size === 'small') {
45 | return css`
46 | border-radius: 30px;
47 | padding: 0.5rem 1rem;
48 | font-size: 1rem;
49 | min-width: 140px;
50 | min-height: 28px;
51 | letter-spacing: 0.2rem;
52 | `
53 | }
54 | }}
55 |
56 | ${({ disabled }) =>
57 | disabled &&
58 | css`
59 | pointer-events: none;
60 | opacity: 0.5;
61 | `}
62 |
63 | ${media.forSmallMediumOnly`
64 | font-size: 1rem;
65 | padding: .75rem 1.75rem;
66 | `}
67 | `
68 |
69 | const StyledButton = styled.button`
70 | ${ButtonStyles};
71 | `
72 |
73 | const StyledLinkButton = styled(Link)`
74 | ${ButtonStyles};
75 | `
76 |
77 | export const Button = ({
78 | loading = false,
79 | size = 'large',
80 | children,
81 | ...rest
82 | }) => {
83 | return (
84 |
85 | {loading ? : children}
86 |
87 | )
88 | }
89 |
90 | export const LinkButton = ({ to, children, ...rest }) => {
91 | return (
92 |
93 | {children}
94 |
95 | )
96 | }
97 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/NavBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Nav } from '@caldera-digital/nav'
3 | import { Link } from 'gatsby'
4 | import styled from 'styled-components'
5 | import { media } from '@caldera-digital/theme'
6 | import Logo from '../assets/svgs/caldera-logo.svg'
7 |
8 | const LOGO_SPACING = '28px'
9 | const LogoContainer = styled(Link)`
10 | display: flex;
11 | align-items: center;
12 |
13 | svg {
14 | height: calc(${props => props.theme.desktopHeaderHeight} - ${LOGO_SPACING});
15 |
16 | ${media.forSmallOnly`
17 | height: calc(${props =>
18 | props.theme.mobileHeaderHeight} - ${LOGO_SPACING});
19 | `};
20 | }
21 | `
22 |
23 | const StyledNav = styled(Nav)`
24 | background-color: ${props => props.theme.white};
25 | box-shadow: 0px 6px 18px 0px rgba(0, 128, 238, 0.15);
26 |
27 | a {
28 | margin-right: 1.25rem;
29 | color: #676767 !important;
30 | font-weight: 400;
31 | text-transform: initial !important;
32 |
33 | &:after {
34 | background-color: ${props => props.theme.secondaryColor} !important;
35 | }
36 | }
37 |
38 | ${media.forSmallMediumOnly`
39 | a {
40 | margin-right: 0.8rem;
41 | }
42 | `}
43 |
44 | ${media.forSmallOnly`
45 | position: fixed;
46 | top: 0;
47 | z-index: 50;
48 | width: 100%;
49 |
50 | a {
51 | margin: 0;
52 | font-size: 1.25rem
53 | }
54 | `}
55 | `
56 |
57 | const routeStyles = {
58 | textTransform: 'uppercase',
59 | }
60 |
61 | export const createRoutes = (location = {}) => [
62 | {
63 | route: '/our-process',
64 | text: 'Our Process',
65 | as: Link,
66 | style: routeStyles,
67 | get selected() {
68 | return this.route === location.pathname
69 | },
70 | },
71 | {
72 | route: '/join-our-team',
73 | text: 'Join Our Team',
74 | as: Link,
75 | style: routeStyles,
76 | get selected() {
77 | return this.route === location.pathname
78 | },
79 | },
80 | {
81 | route: '/contact-us',
82 | text: 'Contact Us',
83 | as: Link,
84 | style: routeStyles,
85 | get selected() {
86 | return this.route === location.pathname
87 | },
88 | },
89 | ]
90 |
91 | export const NavBar = ({ location, theme }) => {
92 | return (
93 | (
97 |
98 |
99 |
100 | )}
101 | />
102 | )
103 | }
104 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Layout, SEO, Hero, GroovyPhone } from '../components'
3 | import { OurServices } from '../components/Homepage/OurServices'
4 | import { Welcome } from '../components/Homepage/Welcome'
5 | import { WhoWeveWorkedWith } from '../components/Homepage/WhoWeveWorkedWith'
6 | import { CallToAction } from '../components/Homepage/CallToAction'
7 | import styled, { keyframes } from 'styled-components'
8 | import { media } from '@caldera-digital/theme'
9 |
10 | export const jiggle = keyframes`
11 | 0% {
12 | transform: scale(1);
13 | }
14 | 50% {
15 | transform: scale(1.08) translate(3px, 3px) rotate(6deg);
16 | }
17 | 100% {
18 | transform: scale(1);
19 | }
20 | `
21 |
22 | const StyledPhoneContainer = styled.div`
23 | max-width: 550px;
24 | width: 100%;
25 | height: 80vh;
26 | margin-right: 5rem;
27 |
28 | ${media.forSmallMediumOnly`
29 | max-width: 400px;
30 | height: 60vh;
31 | margin: 0 0 0 5rem;
32 | `}
33 |
34 | ${media.forSmallMediumOnly`
35 | margin: 0rem;
36 | padding: 2rem 3rem 0 2rem;
37 | `}
38 | `
39 |
40 | export const StyledHeroPhone = styled(GroovyPhone)`
41 | width: 100%;
42 | height: 100%;
43 | overflow: visible;
44 |
45 | /* Little blue */
46 | #Layer_1-8,
47 | #Layer_2-9 {
48 | animation: 8s ${jiggle} infinite;
49 | }
50 |
51 | /* Big teal */
52 | #Layer_2-3,
53 | #Layer_2-2 {
54 | animation: 8s ${jiggle} infinite;
55 | animation-delay: 2s;
56 | }
57 |
58 | /* Big blue */
59 | #Layer_2-4,
60 | #Layer_2 {
61 | animation: 8s ${jiggle} infinite;
62 | animation-delay: 1.5s;
63 | }
64 |
65 | /* Orange */
66 | #Layer_2-6,
67 | #Layer_2-5 {
68 | animation: 8s ${jiggle} infinite;
69 | animation-delay: 1s;
70 | }
71 |
72 | /* Red */
73 | #Layer_2-10,
74 | #Layer_1-7 {
75 | animation: 8s ${jiggle} infinite;
76 | }
77 | `
78 |
79 | const HomePage = ({ location }) => {
80 | return (
81 |
82 |
83 | (
87 |
88 |
89 |
90 | )}
91 | blobs={[]}
92 | />
93 |
94 |
95 |
96 |
97 |
98 | )
99 | }
100 |
101 | export default HomePage
102 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-server/src/stripeCharge.ts:
--------------------------------------------------------------------------------
1 | import { config, firestore } from 'firebase-functions'
2 |
3 | import { db } from './utils/store'
4 |
5 | const stripe = require('stripe')(config().stripe.testsecret)
6 |
7 | // Should go to shared
8 | const calcTotal = (cart = []) =>
9 | // @ts-ignore
10 | cart.reduce((accu, item) => accu + item.price, 0) * 100
11 |
12 | const stripeChargeHandler = async (snap: any, { params }: any) => {
13 | const payment = snap.data()
14 | const userId = params.userId
15 | const paymentId = params.paymentId
16 |
17 | // Return early if there's no payment or there's already a charge
18 | if (!payment || payment.charge) return
19 |
20 | // Grab the user from the user collection
21 | const userSnap = await db
22 | .collection('users')
23 | .doc(userId)
24 | .get()
25 | const user = userSnap.data()
26 |
27 | if (!user) return console.error('Cannot find user!')
28 | const itemsInCart = user.cart.length
29 |
30 | if (itemsInCart === 0) {
31 | return console.error('Cannot charge a customer that has no items in cart!')
32 | }
33 |
34 | // Build the payment object
35 | try {
36 | const userRef = db.collection('users').doc(userId)
37 |
38 | let stripeCustomerID = ''
39 | if (!user.stripeCustomerID) {
40 | // TODO: Fire off events here like analytics or other tracking
41 | console.log('New customer, creating in Stripe...')
42 | const { id } = await stripe.customers.create({
43 | description: `Customer for ${user.firstName} ${user.lastName} (${
44 | user.userId
45 | })`,
46 | source: payment.id,
47 | })
48 |
49 | stripeCustomerID = id
50 | } else {
51 | stripeCustomerID = user.stripeCustomerID
52 | }
53 |
54 | const chargeData = await stripe.charges.create(
55 | {
56 | amount: calcTotal(user.cart),
57 | currency: 'usd',
58 | description: 'A product purchase',
59 | customer: stripeCustomerID,
60 | },
61 | { idempotency_key: paymentId },
62 | )
63 |
64 | const { data: stripeChargeData } = await stripe.charges.list({
65 | customer: stripeCustomerID,
66 | })
67 |
68 | // TODO: This should be a transaction in a production app
69 | await userRef
70 | .collection('payments')
71 | .doc(paymentId)
72 | .update({
73 | chargeData,
74 | })
75 |
76 | await userRef.set(
77 | {
78 | cart: [], // Empty their cart
79 | stripeCharges: stripeChargeData,
80 | stripeCustomerID,
81 | purchases: [
82 | ...user.purchases,
83 | {
84 | items: user.cart,
85 | id: paymentId,
86 | },
87 | ], // Save ref on user object to lookup details later if needed
88 | },
89 | { merge: true },
90 | )
91 | } catch (error) {
92 | console.error('Charge payment failed:', error)
93 | }
94 | }
95 |
96 | export const stripeCharge = firestore
97 | .document('users/{userId}/payments/{paymentId}')
98 | .onCreate(stripeChargeHandler)
99 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-shared/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 |
7 | ## [0.2.4](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-shared@0.2.3...@caldera-digital/ecommerce-stripe-shared@0.2.4) (2019-10-19)
8 |
9 |
10 | ### :bug: Bug Fixes
11 |
12 | * fix loader, add docs, clean data ([760697c](https://github.com/caldera-digital/platform/commit/760697c))
13 |
14 |
15 | ### :sparkles: Features
16 |
17 | * cart, home page, validations, ready for stripe ([220ddc6](https://github.com/caldera-digital/platform/commit/220ddc6))
18 |
19 |
20 |
21 |
22 |
23 |
24 | ## [0.2.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-shared@0.2.1...@caldera-digital/ecommerce-stripe-shared@0.2.3) (2019-08-29)
25 |
26 |
27 | ### :bug: Bug Fixes
28 |
29 | * messed up publish, another bump ([29991b6](https://github.com/caldera-digital/platform/commit/29991b6))
30 |
31 |
32 |
33 |
34 |
35 |
36 | ## [0.2.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-shared@0.1.4...@caldera-digital/ecommerce-stripe-shared@0.2.1) (2019-08-29)
37 |
38 |
39 | ### :sparkles: Features
40 |
41 | * publish all packages, this bumps lerna ([f5f5c9e](https://github.com/caldera-digital/platform/commit/f5f5c9e))
42 |
43 |
44 |
45 |
46 |
47 |
48 | ## [0.1.4](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-shared@0.1.3...@caldera-digital/ecommerce-stripe-shared@0.1.4) (2019-08-29)
49 |
50 |
51 | ### :sparkles: Features
52 |
53 | * security rules, fix for shared, filter published packages ([172fe31](https://github.com/caldera-digital/platform/commit/172fe31))
54 |
55 |
56 |
57 |
58 |
59 |
60 | ## [0.1.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-shared@0.1.2...@caldera-digital/ecommerce-stripe-shared@0.1.3) (2019-08-29)
61 |
62 |
63 | ### :bug: Bug Fixes
64 |
65 | * styling and make package public ([9ec2fe5](https://github.com/caldera-digital/platform/commit/9ec2fe5))
66 |
67 |
68 |
69 |
70 |
71 |
72 | ## [0.1.2](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-shared@0.1.1...@caldera-digital/ecommerce-stripe-shared@0.1.2) (2019-08-29)
73 |
74 |
75 | ### :bug: Bug Fixes
76 |
77 | * no versions so packages arent published, tweak data ([ea30443](https://github.com/caldera-digital/platform/commit/ea30443))
78 |
79 |
80 |
81 |
82 |
83 |
84 | ## 0.1.1 (2019-08-29)
85 |
86 |
87 | ### :sparkles: Features
88 |
89 | * ecom shared, init db script, auth working client ([9306579](https://github.com/caldera-digital/platform/commit/9306579))
90 |
91 |
92 | ### :ticket: Chores
93 |
94 | * shared published because needed by cloud funcs ([fa40f4e](https://github.com/caldera-digital/platform/commit/fa40f4e))
95 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/components/navBar.tsx:
--------------------------------------------------------------------------------
1 | import { Nav } from '@caldera-digital/nav'
2 | import { media } from '@caldera-digital/theme'
3 | import React, { FC, useContext } from 'react'
4 | import { Link, RouteProps, withRouter } from 'react-router-dom'
5 | import { compose } from 'recompose'
6 | import styled, { withTheme } from 'styled-components'
7 |
8 | import { AuthContext } from '../context/AuthContext'
9 | import { APP_NAME } from '../utils/const'
10 |
11 | type RouteConfig = {
12 | pathname: string
13 | logout?: () => void
14 | theme: any
15 | }
16 |
17 | type NavProps = RouteProps & {
18 | theme: any
19 | }
20 |
21 | const StyledNav = styled(Nav)`
22 | background-color: ${props => props.theme.white};
23 | box-shadow: 0px 6px 18px 0px rgba(0, 128, 238, 0.15);
24 |
25 | a {
26 | margin-right: 1.25rem;
27 | color: ${props => props.theme.defaultFontColor} !important;
28 | font-weight: 400;
29 | text-transform: initial !important;
30 |
31 | &:after {
32 | background-color: ${props => props.theme.secondaryColor} !important;
33 | }
34 | }
35 |
36 | ${media.forSmallMediumOnly`
37 | a {
38 | margin-right: 0.8rem;
39 | }
40 | `}
41 |
42 | ${media.forSmallOnly`
43 | position: fixed;
44 | top: 0;
45 | z-index: 50;
46 | width: 100%;
47 |
48 | a {
49 | margin: 0;
50 | font-size: 1.25rem
51 | }
52 |
53 | button {
54 | color: white !important;
55 | }
56 | `}
57 | `
58 |
59 | const routeStyles = {
60 | textTransform: 'uppercase',
61 | }
62 |
63 | export const createRoutes = ({ pathname, logout, theme }: RouteConfig) => [
64 | {
65 | route: '/',
66 | text: 'Home',
67 | as: Link,
68 | style: routeStyles,
69 | get selected() {
70 | return this.route === pathname
71 | },
72 | },
73 | {
74 | route: '/cart',
75 | text: 'Cart',
76 | as: Link,
77 | style: routeStyles,
78 | get selected() {
79 | return this.route === pathname
80 | },
81 | },
82 | ...(logout
83 | ? [
84 | {
85 | route: '',
86 | onClick: logout,
87 | text: 'Logout',
88 | as: 'button',
89 | style: {
90 | ...routeStyles,
91 | borderRadius: '5px',
92 | background: theme.primaryColor,
93 | border: 'none',
94 | padding: '.5rem',
95 | margin: 0,
96 | },
97 | get selected() {
98 | return this.route === pathname
99 | },
100 | },
101 | ]
102 | : []),
103 | ]
104 |
105 | const NavBarComponent: FC = ({ location, theme }) => {
106 | const { logout } = useContext(AuthContext)
107 |
108 | return (
109 | (
117 | {APP_NAME}
118 | )}
119 | />
120 | )
121 | }
122 |
123 | export const NavBar = compose(
124 | withTheme,
125 | withRouter,
126 | )(NavBarComponent)
127 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Seo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This react helmet code is adapted from
3 | * https://themeteorchef.com/tutorials/reusable-seo-with-react-helmet.
4 | *
5 | * A great tutorial explaining how to setup a robust version of an
6 | * SEO friendly react-helmet instance.
7 | *
8 | *
9 | * Use the Helmet on pages to generate SEO and meta content!
10 | *
11 | * Usage:
12 | *
17 | *
18 | */
19 |
20 | import React from 'react'
21 | import Helmet from 'react-helmet'
22 | import { graphql, useStaticQuery } from 'gatsby'
23 |
24 | const seoQuery = graphql`
25 | {
26 | allSite {
27 | edges {
28 | node {
29 | siteMetadata {
30 | description
31 | social {
32 | name
33 | url
34 | }
35 | siteUrl
36 | title
37 | name
38 | }
39 | }
40 | }
41 | }
42 | }
43 | `
44 |
45 | export const SEO = ({
46 | title,
47 | description,
48 | children,
49 | url,
50 | image = 'https://res.cloudinary.com/calderablog/image/upload/v1564971507/social-link_crvqll.png',
51 | published,
52 | pathname,
53 | timeToRead,
54 | }) => {
55 | const results = useStaticQuery(seoQuery)
56 | const site = results.allSite.edges[0].node.siteMetadata
57 | const twitter = site.social.find(option => option.name === 'twitter') || {}
58 |
59 | const fullURL = path => (path ? `${site.siteUrl}${path}` : site.siteUrl)
60 | const fullPageTitle = title ? `${title} | ${site.name}` : site.title
61 |
62 | const metaTags = [
63 | { charset: 'utf-8' },
64 | {
65 | 'http-equiv': 'X-UA-Compatible',
66 | content: 'IE=edge',
67 | },
68 | {
69 | name: 'viewport',
70 | content: 'width=device-width, initial-scale=1',
71 | },
72 | {
73 | name: 'theme-color',
74 | content: '#fff',
75 | },
76 | {
77 | rel: 'canonical',
78 | href: fullURL(pathname),
79 | },
80 | { itemprop: 'name', content: fullPageTitle },
81 | { itemprop: 'description', content: description || site.description },
82 | { itemprop: 'image', content: image },
83 | { name: 'description', content: description || site.description },
84 |
85 | { name: 'twitter:card', content: 'summary_large_image' },
86 | { name: 'twitter:site', content: site.name },
87 | { name: 'twitter:title', content: fullPageTitle },
88 | { name: 'twitter:description', content: description || site.description },
89 | { name: 'twitter:creator', content: twitter.url },
90 | {
91 | name: 'twitter:image',
92 | content: image,
93 | },
94 |
95 | { property: 'og:title', content: fullPageTitle },
96 | { property: 'og:url', content: url },
97 | { property: 'og:image', content: image },
98 | { property: 'og:description', content: description || site.description },
99 | { property: 'og:site_name', content: site.name },
100 | ]
101 |
102 | if (published) {
103 | metaTags.push({ name: 'article:published_time', content: published })
104 | }
105 |
106 | if (timeToRead) {
107 | metaTags.push({ name: 'twitter:label1', value: 'Reading time' })
108 | metaTags.push({ name: 'twitter:data1', value: timeToRead })
109 | }
110 |
111 | return (
112 |
117 | {children}
118 |
119 | )
120 | }
121 |
--------------------------------------------------------------------------------
/projects/caldera-www/gatsby-config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 | module.exports = {
3 | siteMetadata: {
4 | title: 'Caldera | You Dream it. We Bring it to Life.',
5 | name: 'Caldera',
6 | siteUrl: 'https://calderadigital.com/',
7 | description:
8 | 'Caldera is a product and application development agency that uses innovative technology to bring your vision, brand, and identity to life through human-centered design practices.',
9 | hero: {
10 | heading: 'The Caldera blog.',
11 | maxWidth: 652,
12 | },
13 | social: [
14 | {
15 | name: 'twitter',
16 | url: 'https://twitter.com/caldera_digital',
17 | },
18 | {
19 | name: 'github',
20 | url: 'https://github.com/caldera-digital',
21 | },
22 | {
23 | name: 'instagram',
24 | url: 'https://www.instagram.com/calderadigital/',
25 | },
26 | // {
27 | // name: 'linkedin',
28 | // url: 'https://www.linkedin.com/company/narative/',
29 | // },
30 | // {
31 | // name: 'dribbble',
32 | // url: 'https://dribbble.com/narativestudio',
33 | // },
34 | ],
35 | },
36 | plugins: [
37 | {
38 | resolve: 'gatsby-source-filesystem',
39 | options: {
40 | path: `${__dirname}/src`,
41 | name: 'src',
42 | },
43 | },
44 | {
45 | resolve: 'gatsby-plugin-google-analytics',
46 | options: {
47 | trackingId: 'UA-120914445-1',
48 | },
49 | },
50 | {
51 | resolve: 'gatsby-plugin-manifest',
52 | options: {
53 | // TODO
54 | name: 'Caldera | We Create Outstanding Experiences',
55 | short_name: 'Caldera',
56 | start_url: '/',
57 | background_color: '#FFFFFF',
58 | theme_color: '#0080EE',
59 | display: 'minimal-ui',
60 | icon: 'src/favicon.png',
61 | },
62 | },
63 | {
64 | resolve: 'gatsby-plugin-react-svg',
65 | options: {
66 | rule: {
67 | include: /svgs/,
68 | },
69 | },
70 | },
71 | {
72 | resolve: 'gatsby-plugin-styled-components',
73 | options: {},
74 | },
75 | 'gatsby-plugin-offline',
76 | 'gatsby-plugin-react-helmet',
77 | 'gatsby-plugin-sitemap',
78 | 'gatsby-plugin-netlify',
79 | 'gatsby-transformer-sharp',
80 | 'gatsby-plugin-sharp',
81 | {
82 | resolve: 'gatsby-plugin-disqus',
83 | options: {
84 | shortname: 'calderadigital',
85 | },
86 | },
87 | {
88 | resolve: 'gatsby-plugin-mailchimp',
89 | options: {
90 | endpoint:
91 | 'https://calderadigital.us18.list-manage.com/subscribe/post?u=4c88cd983f586a817f4b1b345&id=0ed9147da3',
92 | },
93 | },
94 | {
95 | resolve: 'gatsby-plugin-polyfill-io',
96 | options: {
97 | features: ['Promise', 'Array.prototype.forEach'],
98 | },
99 | },
100 | {
101 | resolve: 'gatsby-plugin-sentry',
102 | options: {
103 | dsn: 'https://8d2d575dedeb41f989e0cc19e83aaa0e@sentry.io/1523590',
104 | // Optional settings, see https://docs.sentry.io/clients/node/config/#optional-settings
105 | environment: process.env.NODE_ENV,
106 | enabled: (() =>
107 | ['production', 'stage'].indexOf(process.env.NODE_ENV) !== -1)(),
108 | },
109 | },
110 | {
111 | resolve: 'gatsby-plugin-canonical-urls',
112 | options: {
113 | siteUrl: 'https://calderadigital.com',
114 | },
115 | },
116 | ],
117 | }
118 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Caldera Digital Platform 🏕
2 |
3 | All open source libraries and projects from the Caldera team. All documentation is accessible on the documentation website or through React Cosmos.
4 |
5 | ## Getting Started
6 |
7 | ```sh
8 | git clone https://github.com/caldera-digital/platform.git
9 |
10 | cd platform
11 |
12 | npm install typescript@3.5.3 -g
13 |
14 | # Only if you want to serve functions locally
15 | npm install firebase-tools@7.2.4 -g
16 |
17 | # Installs deps and builds all packages and projects
18 | yarn bootstrap
19 |
20 | yarn :dev
21 | ```
22 |
23 | ## Recommended Environment
24 |
25 | 1. VSCode
26 | 2. Install [VSCode Live Share](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare-pack)
27 | 3. [ZSH](https://ohmyz.sh/)
28 | 4. Install [NVM](https://github.com/nvm-sh/nvm)
29 | 5. Make sure to install and run the correct version of node when developing on this project
30 |
31 | ```sh
32 | nvm install lts/dubnium
33 | nvm alias default lts/dubnium
34 |
35 | ## If you need to switch back to it
36 | nvm use
37 | ```
38 |
39 | 5. Use [HomeBrew](https://brew.sh/)
40 | 6. Use [yarn](https://yarnpkg.com/en/)
41 |
42 | ```sh
43 | brew install yarn
44 | ```
45 |
46 | Feel free to use any terminal. However, if pair programming with LiveShare you will need to use the integrated VSCode terminal.
47 |
48 | ## Coding Standards with VSCode
49 |
50 | You do not have to use VSCode in order to develop on this project, but it is highly recommended. Before we begin, please install the following plugins:
51 |
52 | 1. [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)
53 | 2. [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
54 | 3. [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
55 | 4. [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)
56 |
57 | There are workspace settings for this repo located in [`.vscode/settings.json`](./.vscode/settings.json) that will format all files you create or edit on save according to the rules defined in `.prettierrc`, `.editorconfig`, and `.eslintrc` files. There is also a running list of spell check exceptions. You can override these settings with your user settings if needed.
58 |
59 | If you need to add a global variable, insert it into the `.eslintrc` file. Sometimes you need to break the rules for some of the lines of code. If you need to do that you can right click on the broken rules in the code and disable that rule for that line. It's helpful to disable the rule for the line of code so others can see why it's needed.
60 |
61 | ### Workspaces
62 |
63 | There is a workspace available for each project located in [`.vscode/caldera-platform.code-workspace`](./.vscode/caldera-platform.code-workspace). It is helpful to run this so you can receive topical search results that ignore built files or test coverage directories. It also changes your title bar color so you can easily find this project compared to other coding windows you have open.
64 |
65 | ## Adding Firebase Secrets
66 |
67 | In order to add secrets to a Firebase project you need to be logged in and authorized to do so by the project. All of this is done though the cli with the following command:
68 |
69 | ```sh
70 | # Cannot use uppercase!
71 | firebase functions:config:set stripe.testsecret="your-test-secret-key"
72 |
73 | # Deploy your updates
74 | firebase deploy --only functions
75 | ```
76 |
77 | You can then get to it in your cloud functions like so:
78 |
79 | ```js
80 | import { config } from 'firebase-functions'
81 |
82 | const secret = config().stripe.testsecret
83 | ```
84 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/ImageLinkSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { Link } from 'gatsby'
4 | import { media } from '@caldera-digital/theme'
5 |
6 | import ArrowRight from '../assets/svgs/arrow-right.svg'
7 |
8 | const WORK_DETAIL_HEIGHT = '350px'
9 | const WORK_OVERFLOW = '125px'
10 | const IMAGE_HEIGHT = `${WORK_DETAIL_HEIGHT} + ${WORK_OVERFLOW}`
11 | const StyledImageLinkSection = styled.div`
12 | background-color: rgba(0, 128, 238, 0.07);
13 | height: ${WORK_DETAIL_HEIGHT};
14 | border-radius: 30px;
15 | padding: 2rem 3rem;
16 | display: flex;
17 | align-items: center;
18 | margin: ${`calc(${WORK_OVERFLOW} / 2 + 3rem) 0`};
19 | flex-direction: ${props => (props.reverse ? 'row-reverse' : 'row')};
20 |
21 | h3 {
22 | font-weight: bold;
23 | color: ${props => props.theme.black};
24 | margin-bottom: 1.5rem;
25 | font-size: 1.5rem;
26 | }
27 |
28 | > a {
29 | width: 40%;
30 | padding: ${props => (props.reverse ? '0 0 0 1rem' : '0 1rem 0 0')};
31 |
32 | img {
33 | height: ${`calc(${IMAGE_HEIGHT})`};
34 | object-fit: contain;
35 | position: relative;
36 | width: 100%;
37 | }
38 | }
39 |
40 | > div {
41 | width: 60%;
42 | }
43 |
44 | ${media.forSmallMediumOnly`
45 | flex-direction: column;
46 | height: auto;
47 | position: relative;
48 | padding-top: ${`calc((${IMAGE_HEIGHT}) / 2)`};
49 | margin-top: ${`calc((${IMAGE_HEIGHT}) / 2)`};
50 |
51 | > a {
52 | position: absolute;
53 | /* Note the - for negative */
54 | top: ${`calc((${IMAGE_HEIGHT}) / -2)`};
55 | width: 40%;
56 | }
57 |
58 | > div {
59 | width: 100%;
60 | }
61 | `}
62 |
63 | ${media.forSmallOnly`
64 | border-radius: ${props =>
65 | props.reverse ? '30px 0 0 30px' : '0 30px 30px 0'};
66 | margin-left: ${props => (props.reverse ? '3rem' : '0')};
67 | margin-right: ${props => (props.reverse ? '0' : '3rem')};
68 |
69 | > a {
70 | width: 60%;
71 | }
72 | `}
73 |
74 | @media (max-width: 400px) {
75 | > a {
76 | width: 80%;
77 | }
78 | }
79 | `
80 |
81 | const OUR_WORK_NAV_BUTTON_SIZE = '55px'
82 | const OurWorkNavButton = styled.span`
83 | display: none;
84 |
85 | svg {
86 | width: ${OUR_WORK_NAV_BUTTON_SIZE};
87 | height: ${OUR_WORK_NAV_BUTTON_SIZE};
88 | }
89 |
90 | ${media.forSmallMediumOnly`
91 | display: block;
92 | position: absolute;
93 | /* Note the - for negative */
94 | bottom: ${`calc(${OUR_WORK_NAV_BUTTON_SIZE} / -2)`};
95 | right: ${props =>
96 | props.reverse
97 | ? `calc(100% + (${OUR_WORK_NAV_BUTTON_SIZE} / -2))`
98 | : `calc(${OUR_WORK_NAV_BUTTON_SIZE} / -2)`};
99 | `}
100 | `
101 |
102 | export const ImageLinkSection = ({
103 | imageConfig,
104 | title,
105 | description,
106 | to,
107 | reverse,
108 | className = '',
109 | }) => {
110 | return (
111 |
112 | {imageConfig && (
113 |
114 | {/* eslint-disable-next-line jsx-a11y/alt-text */}
115 |
116 |
117 | )}
118 |
119 |
120 | {title}
121 |
122 | {/* May need to check if function eventually */}
123 | {description()}
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | )
132 | }
133 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/pages/CartPage/CheckoutForm.tsx:
--------------------------------------------------------------------------------
1 | import { Button, message, Modal } from 'antd'
2 | import React, { FC, useEffect, useState } from 'react'
3 | import { RouteComponentProps, withRouter } from 'react-router-dom'
4 | import {
5 | CardElement,
6 | injectStripe,
7 | ReactStripeElements,
8 | } from 'react-stripe-elements'
9 | import { compose } from 'recompose'
10 |
11 | import { Error } from '../../components'
12 | import firebase from '../../config/firebase'
13 | import { User } from '../../types'
14 | import { getPurchaseByFirebaseID } from '../../utils/utilityService'
15 |
16 | const db = firebase.firestore()
17 |
18 | type P = RouteComponentProps &
19 | ReactStripeElements.InjectedStripeProps & {
20 | user: User
21 | }
22 |
23 | type SubmitPayment = {
24 | stripe: ReactStripeElements.StripeProps
25 | user: User
26 | setProcessingPayment: (isProcessingPayment: boolean) => any
27 | setPaymentFirebaseID: (id: string) => any
28 | }
29 |
30 | // Place outside of render for easy unit testing
31 | const submitPayment = async ({
32 | stripe,
33 | user,
34 | setProcessingPayment,
35 | setPaymentFirebaseID,
36 | }: SubmitPayment) => {
37 | setProcessingPayment(true)
38 |
39 | const { token } = await stripe.createToken({ name: user.displayName })
40 |
41 | if (!token) {
42 | setProcessingPayment(false)
43 | return message.error(
44 | 'Could not charge your payment. Are you sure the card number is correct?',
45 | )
46 | }
47 |
48 | try {
49 | const { id } = await db
50 | .collection('users')
51 | .doc(user.userId)
52 | .collection('payments')
53 | .add(token)
54 |
55 | setPaymentFirebaseID(id)
56 | } catch (error) {
57 | setProcessingPayment(false)
58 | message.error('Could not charge your payment. Please try again.')
59 | }
60 |
61 | console.log(token)
62 | }
63 |
64 | export const CheckoutFormComponent: FC = ({ user, stripe, history }) => {
65 | const [isModalVisible, setModalVisible] = useState(false)
66 | const [isProcessingPayment, setProcessingPayment] = useState(false)
67 | const [paymentFirebaseID, setPaymentFirebaseID] = useState('')
68 | const { purchases } = user
69 |
70 | useEffect(() => {
71 | if (!paymentFirebaseID || !isProcessingPayment) return
72 |
73 | const completedPurchase = getPurchaseByFirebaseID(
74 | purchases,
75 | paymentFirebaseID,
76 | )
77 |
78 | if (completedPurchase) {
79 | message.success(
80 | `Your order has successfully been placed: ${completedPurchase.id}`,
81 | )
82 |
83 | history.push(`/thank-you/${completedPurchase.id}`)
84 | }
85 | })
86 |
87 | if (!stripe) return
88 | return (
89 |
90 |
setModalVisible(true)}
94 | >
95 | Checkout
96 |
97 |
98 |
101 | submitPayment({
102 | stripe,
103 | user,
104 | setProcessingPayment,
105 | setPaymentFirebaseID,
106 | })
107 | }
108 | confirmLoading={isProcessingPayment}
109 | onCancel={() => setModalVisible(false)}
110 | >
111 | Purchase Order
112 |
113 | Please input your credit card information for us to process your
114 | order.
115 |
116 |
117 |
118 |
119 | )
120 | }
121 |
122 | export const CheckoutForm = compose(
123 | withRouter,
124 | injectStripe,
125 | )(CheckoutFormComponent)
126 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-server/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 |
7 | ## [0.2.4](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-server@0.2.3...@caldera-digital/ecommerce-stripe-server@0.2.4) (2019-10-19)
8 |
9 |
10 | ### :bug: Bug Fixes
11 |
12 | * safer user object ([5aaf889](https://github.com/caldera-digital/platform/commit/5aaf889))
13 | * tweaks for build ([b038fdc](https://github.com/caldera-digital/platform/commit/b038fdc))
14 |
15 |
16 | ### :sparkles: Features
17 |
18 | * add Stripe customer, payment amount, and Stripe charge id ([7e0eebc](https://github.com/caldera-digital/platform/commit/7e0eebc))
19 | * cart, home page, validations, ready for stripe ([220ddc6](https://github.com/caldera-digital/platform/commit/220ddc6))
20 | * payments working! Thank you page, backend flow, cleanup ([3e8d8a8](https://github.com/caldera-digital/platform/commit/3e8d8a8))
21 | * start on stripe, login page, cleanup, initdb ([ad69311](https://github.com/caldera-digital/platform/commit/ad69311))
22 |
23 |
24 |
25 |
26 |
27 |
28 | ## [0.2.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-server@0.2.1...@caldera-digital/ecommerce-stripe-server@0.2.3) (2019-08-29)
29 |
30 |
31 | ### :bug: Bug Fixes
32 |
33 | * messed up publish, another bump ([29991b6](https://github.com/caldera-digital/platform/commit/29991b6))
34 |
35 |
36 |
37 |
38 |
39 |
40 | ## [0.2.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-server@0.1.1...@caldera-digital/ecommerce-stripe-server@0.2.1) (2019-08-29)
41 |
42 |
43 | ### :bug: Bug Fixes
44 |
45 | * no versions so packages arent published, tweak data ([ea30443](https://github.com/caldera-digital/platform/commit/ea30443))
46 |
47 |
48 | ### :sparkles: Features
49 |
50 | * nav, logout, all pages, theming, normalize, match versions ([cb90f0e](https://github.com/caldera-digital/platform/commit/cb90f0e))
51 | * publish all packages, this bumps lerna ([f5f5c9e](https://github.com/caldera-digital/platform/commit/f5f5c9e))
52 | * security rules, fix for shared, filter published packages ([172fe31](https://github.com/caldera-digital/platform/commit/172fe31))
53 |
54 |
55 | ### :ticket: Chores
56 |
57 | * **release:** publish ([e3cb2f8](https://github.com/caldera-digital/platform/commit/e3cb2f8))
58 |
59 |
60 |
61 |
62 |
63 |
64 | ## [0.1.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-server@0.1.1...@caldera-digital/ecommerce-stripe-server@0.1.1) (2019-08-29)
65 |
66 |
67 | ### :bug: Bug Fixes
68 |
69 | * no versions so packages arent published, tweak data ([ea30443](https://github.com/caldera-digital/platform/commit/ea30443))
70 |
71 |
72 | ### :sparkles: Features
73 |
74 | * nav, logout, all pages, theming, normalize, match versions ([cb90f0e](https://github.com/caldera-digital/platform/commit/cb90f0e))
75 | * security rules, fix for shared, filter published packages ([172fe31](https://github.com/caldera-digital/platform/commit/172fe31))
76 |
77 |
78 |
79 |
80 |
81 |
82 | ## 0.1.1 (2019-08-29)
83 |
84 |
85 | ### :sparkles: Features
86 |
87 | * bootstrap, ecommerce stripe platform with typescript ([d9ea004](https://github.com/caldera-digital/platform/commit/d9ea004))
88 | * ecom shared, init db script, auth working client ([9306579](https://github.com/caldera-digital/platform/commit/9306579))
89 | * on create user cloud function ([0253759](https://github.com/caldera-digital/platform/commit/0253759))
90 | * skeleton for front, setup back in monorepo, all running! ([a2e63fc](https://github.com/caldera-digital/platform/commit/a2e63fc))
91 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Homepage/OurServices.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Section } from '../Section'
3 | import styled from 'styled-components'
4 | import { media } from '@caldera-digital/theme'
5 | import Carousel from '@brainhubeu/react-carousel'
6 |
7 | import Analytics from '../../assets/svgs/analytics.svg'
8 | import Apps from '../../assets/svgs/apps.svg'
9 | import Web from '../../assets/svgs/web.svg'
10 |
11 | import '@brainhubeu/react-carousel/lib/style.css'
12 |
13 | const CarouselItem = styled.div`
14 | border-radius: 60px;
15 | box-shadow: 0 3px 17px rgba(54, 163, 252, 0.2);
16 | min-height: 420px;
17 | width: 100%;
18 | margin: 1rem;
19 | padding: 3rem;
20 | display: flex;
21 | align-items: center;
22 | justify-content: center;
23 | background-color: ${props => props.theme.white};
24 |
25 | > svg {
26 | width: 30%;
27 | margin-right: 2rem;
28 | }
29 |
30 | > div {
31 | flex: 1;
32 |
33 | h3 {
34 | font-weight: bold;
35 | font-size: 2rem;
36 | margin-bottom: 1rem;
37 | }
38 |
39 | p {
40 | font-weight: 300;
41 | font-size: 1.2rem;
42 | }
43 | }
44 |
45 | ${media.forSmallMediumOnly`
46 | flex-direction: column;
47 | min-height: 550px;
48 |
49 | > svg {
50 | margin: 0 0 2rem;
51 | }
52 |
53 | > div {
54 | h3 {
55 | font-size: 1.75rem;
56 | }
57 |
58 | p {
59 | font-size: 1rem;
60 | }
61 | }
62 | `}
63 |
64 | ${media.forSmallOnly`
65 | flex-direction: column;
66 | min-height: 670px;
67 |
68 | > svg {
69 | width: 50%;
70 | }
71 |
72 | > div {
73 | h3 {
74 | font-size: 1.5rem;
75 | }
76 | }
77 | `}
78 | `
79 |
80 | export const OurServices = () => {
81 | const [currentIndex, setCurrentIndex] = React.useState(0)
82 |
83 | return (
84 | (
88 | setCurrentIndex(index)}
99 | breakpoints={{
100 | 991: {
101 | slidesPerPage: 1,
102 | },
103 | 680: {
104 | slidesPerPage: 1,
105 | },
106 | }}
107 | >
108 |
109 |
110 |
111 |
Mobile Applications
112 |
113 | A mobile app's success and technical aspects lie in the answers
114 | to these three initial questions: Who will it serve? What will
115 | it be? And what will it do? With our human-centric and high-tech
116 | approach to application development, we ensure that what we
117 | build is more than just code. Our apps progress with
118 | technological innovation - which means they will never be
119 | out-of-date.
120 |
121 |
122 |
123 |
124 |
125 |
126 |
Automation
127 |
128 | If it can be repeated, it can be automated. We employ a variety
129 | of techniques to make repetitive tasks easy as pressing a
130 | button. Whether it be creating a spreadsheet plugin or pulling
131 | data to showcase on a real time dashboard, we have you covered.
132 |
133 |
134 |
135 |
136 |
137 |
138 |
Web Applications
139 |
140 | We will help your business stand out with our innovative
141 | designs, responsive web pages, and phenomenal user experience.
142 | Technology is constantly improving, and your site will too with
143 | progressive updates and eye-catching graphic design. Your
144 | business is the masterpiece of your mind - and we are the team
145 | to bring it to life.
146 |
147 |
148 |
149 |
150 | )}
151 | />
152 | )
153 | }
154 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/pages/contact-us.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | Layout,
4 | SEO,
5 | Button,
6 | Input,
7 | Textarea,
8 | NetlifyForm,
9 | } from '../components'
10 | import styled from 'styled-components'
11 | import { Container, media } from '@caldera-digital/theme'
12 | import { navigateTo } from 'gatsby'
13 | import { emailIsValid } from '../utils/formUtils'
14 | import { BlobHandler, COMMON_BLOB_STYLES } from '../components/Blob'
15 |
16 | import Blob from '../assets/svgs/blue-blob2.svg'
17 | import Blob2 from '../assets/svgs/blue-blob4.svg'
18 |
19 | const StyledLayout = styled(Layout)`
20 | ${COMMON_BLOB_STYLES}
21 |
22 | ${media.forSmallOnly`
23 | svg {
24 | display: none;
25 | }
26 | `}
27 | `
28 |
29 | export const ContactThankYouContainer = styled(Container)`
30 | margin: 5rem auto 6rem;
31 | min-height: calc(100vh - 11rem - ${props => props.theme.desktopHeaderHeight});
32 |
33 | h1 {
34 | font-size: 3rem;
35 | font-weight: bold;
36 | margin-bottom: 2rem;
37 | }
38 |
39 | ${media.forSmallOnly`
40 | min-height: calc(100vh - 11rem);
41 |
42 | h1 {
43 | font-size: 2.5rem;
44 | padding-top: 2rem;
45 | }
46 | `}
47 | `
48 |
49 | const SubmitButton = styled(Button)`
50 | margin-top: 2rem;
51 |
52 | ${media.forSmallOnly`
53 | margin: 2rem auto 0;
54 | `}
55 | `
56 |
57 | const FORM_NAME = 'contact'
58 | const ContactUs = ({ location }) => {
59 | return (
60 |
61 |
62 |
68 |
69 |
70 | Contact Us
71 | !val && 'Name is required.',
80 | email: val =>
81 | (!val || !emailIsValid(val)) && 'Must be a valid email.',
82 | message: val => !val && 'Message is required.',
83 | }}
84 | onFormSubmit={() => navigateTo('/thank-you')}
85 | formName={FORM_NAME}
86 | >
87 | {({
88 | onChange,
89 | onBlur,
90 | isValid,
91 | handleSubmit,
92 | errors,
93 | values,
94 | touched,
95 | }) => (
96 |
146 | )}
147 |
148 |
149 |
150 | )
151 | }
152 |
153 | export default ContactUs
154 |
--------------------------------------------------------------------------------
/packages/theme/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 |
7 | ## [1.0.6](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@1.0.5...@caldera-digital/theme@1.0.6) (2019-08-29)
8 |
9 |
10 | ### :sparkles: Features
11 |
12 | * home page complete desktop and mobile with big refactor ([7985aae](https://github.com/caldera-digital/platform/commit/7985aae))
13 | * sEO, our work page, lots of tweaks ([e85854c](https://github.com/caldera-digital/platform/commit/e85854c))
14 |
15 |
16 |
17 |
18 |
19 |
20 | ## [1.0.5](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@1.0.4...@caldera-digital/theme@1.0.5) (2019-05-31)
21 |
22 |
23 | ### :bug: Bug Fixes
24 |
25 | * bump versions to right level ([ab845a8](https://github.com/caldera-digital/platform/commit/ab845a8))
26 |
27 |
28 |
29 |
30 |
31 |
32 | ## [1.0.4](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@1.0.3...@caldera-digital/theme@1.0.4) (2019-05-08)
33 |
34 |
35 | ### :bug: Bug Fixes
36 |
37 | * fix scripts for theme ([3821d36](https://github.com/caldera-digital/platform/commit/3821d36))
38 |
39 |
40 |
41 |
42 |
43 |
44 | ## [1.0.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@1.0.2...@caldera-digital/theme@1.0.3) (2019-05-05)
45 |
46 |
47 | ### :sparkles: Features
48 |
49 | * wirre up more variables correctly ([883d7dc](https://github.com/caldera-digital/platform/commit/883d7dc))
50 |
51 |
52 |
53 |
54 |
55 |
56 | ## [1.0.2](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@1.0.1...@caldera-digital/theme@1.0.2) (2019-05-05)
57 |
58 |
59 | ### :sparkles: Features
60 |
61 | * add default header font variable ([efee41d](https://github.com/caldera-digital/platform/commit/efee41d))
62 |
63 |
64 |
65 |
66 |
67 |
68 | ## [1.0.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.8...@caldera-digital/theme@1.0.1) (2019-05-05)
69 |
70 |
71 | ### :sparkles: Features
72 |
73 | * add container and 1.0 bump for all ([d9df7a2](https://github.com/caldera-digital/platform/commit/d9df7a2))
74 |
75 |
76 |
77 |
78 |
79 |
80 | ## [0.1.8](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.6...@caldera-digital/theme@0.1.8) (2019-05-04)
81 |
82 |
83 | ### :ticket: Chores
84 |
85 | * add release script ([a833af1](https://github.com/caldera-digital/platform/commit/a833af1))
86 |
87 |
88 |
89 |
90 |
91 |
92 | ## [0.1.6](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.5...@caldera-digital/theme@0.1.6) (2019-05-04)
93 |
94 |
95 | ### :sparkles: Features
96 |
97 | * fix imports for nav and theme ([f0dc63b](https://github.com/caldera-digital/platform/commit/f0dc63b))
98 |
99 |
100 |
101 |
102 |
103 |
104 | ## [0.1.5](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.4...@caldera-digital/theme@0.1.5) (2019-05-03)
105 |
106 |
107 | ### :ticket: Chores
108 |
109 | * trying again ([cd27602](https://github.com/caldera-digital/platform/commit/cd27602))
110 |
111 |
112 |
113 |
114 |
115 |
116 | ## [0.1.4](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.3...@caldera-digital/theme@0.1.4) (2019-05-03)
117 |
118 |
119 | ### :ticket: Chores
120 |
121 | * config update ([237b252](https://github.com/caldera-digital/platform/commit/237b252))
122 |
123 |
124 |
125 |
126 |
127 |
128 | ## [0.1.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.2...@caldera-digital/theme@0.1.3) (2019-05-03)
129 |
130 |
131 | ### :ticket: Chores
132 |
133 | * remove baby change ([af6bd51](https://github.com/caldera-digital/platform/commit/af6bd51))
134 |
135 |
136 |
137 |
138 |
139 |
140 | ## [0.1.2](https://github.com/caldera-digital/platform/compare/@caldera-digital/theme@0.1.1...@caldera-digital/theme@0.1.2) (2019-05-03)
141 |
142 |
143 | ### :ticket: Chores
144 |
145 | * add license baby change ([837bd04](https://github.com/caldera-digital/platform/commit/837bd04))
146 |
147 |
148 |
149 |
150 |
151 |
152 | ## 0.1.1 (2019-05-03)
153 |
154 |
155 | ### :sparkles: Features
156 |
157 | * add cosmos, fix configs, fix nav, add theme ([1fc5896](https://github.com/caldera-digital/platform/commit/1fc5896))
158 |
159 |
160 | ### :ticket: Chores
161 |
162 | * add readme and sort package jsons ([418f93b](https://github.com/caldera-digital/platform/commit/418f93b))
163 | * linter fixes ([5165b98](https://github.com/caldera-digital/platform/commit/5165b98))
164 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 |
7 | ## [0.2.8](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.2.7...@caldera-digital/ecommerce-stripe-client@0.2.8) (2019-12-14)
8 |
9 | **Note:** Version bump only for package @caldera-digital/ecommerce-stripe-client
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## [0.2.7](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.2.6...@caldera-digital/ecommerce-stripe-client@0.2.7) (2019-10-19)
17 |
18 | **Note:** Version bump only for package @caldera-digital/ecommerce-stripe-client
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## [0.2.6](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.2.5...@caldera-digital/ecommerce-stripe-client@0.2.6) (2019-10-19)
26 |
27 | **Note:** Version bump only for package @caldera-digital/ecommerce-stripe-client
28 |
29 |
30 |
31 |
32 |
33 |
34 | ## [0.2.5](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.2.4...@caldera-digital/ecommerce-stripe-client@0.2.5) (2019-10-19)
35 |
36 | **Note:** Version bump only for package @caldera-digital/ecommerce-stripe-client
37 |
38 |
39 |
40 |
41 |
42 |
43 | ## [0.2.4](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.2.3...@caldera-digital/ecommerce-stripe-client@0.2.4) (2019-10-19)
44 |
45 |
46 | ### :bug: Bug Fixes
47 |
48 | * fix loader, add docs, clean data ([760697c](https://github.com/caldera-digital/platform/commit/760697c))
49 |
50 |
51 | ### :sparkles: Features
52 |
53 | * add Stripe customer, payment amount, and Stripe charge id ([7e0eebc](https://github.com/caldera-digital/platform/commit/7e0eebc))
54 | * cart, home page, validations, ready for stripe ([220ddc6](https://github.com/caldera-digital/platform/commit/220ddc6))
55 | * payments working! Thank you page, backend flow, cleanup ([3e8d8a8](https://github.com/caldera-digital/platform/commit/3e8d8a8))
56 | * start on stripe, login page, cleanup, initdb ([ad69311](https://github.com/caldera-digital/platform/commit/ad69311))
57 |
58 |
59 | ### :ticket: Chores
60 |
61 | * tweak for the build ([8a02990](https://github.com/caldera-digital/platform/commit/8a02990))
62 |
63 |
64 |
65 |
66 |
67 |
68 | ## [0.2.3](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.2.1...@caldera-digital/ecommerce-stripe-client@0.2.3) (2019-08-29)
69 |
70 |
71 | ### :bug: Bug Fixes
72 |
73 | * messed up publish, another bump ([29991b6](https://github.com/caldera-digital/platform/commit/29991b6))
74 |
75 |
76 |
77 |
78 |
79 |
80 | ## [0.2.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.1.1...@caldera-digital/ecommerce-stripe-client@0.2.1) (2019-08-29)
81 |
82 |
83 | ### :bug: Bug Fixes
84 |
85 | * no versions so packages arent published, tweak data ([ea30443](https://github.com/caldera-digital/platform/commit/ea30443))
86 |
87 |
88 | ### :sparkles: Features
89 |
90 | * nav, logout, all pages, theming, normalize, match versions ([cb90f0e](https://github.com/caldera-digital/platform/commit/cb90f0e))
91 | * publish all packages, this bumps lerna ([f5f5c9e](https://github.com/caldera-digital/platform/commit/f5f5c9e))
92 | * security rules, fix for shared, filter published packages ([172fe31](https://github.com/caldera-digital/platform/commit/172fe31))
93 |
94 |
95 | ### :ticket: Chores
96 |
97 | * **release:** publish ([e3cb2f8](https://github.com/caldera-digital/platform/commit/e3cb2f8))
98 |
99 |
100 |
101 |
102 |
103 |
104 | ## [0.1.1](https://github.com/caldera-digital/platform/compare/@caldera-digital/ecommerce-stripe-client@0.1.1...@caldera-digital/ecommerce-stripe-client@0.1.1) (2019-08-29)
105 |
106 |
107 | ### :bug: Bug Fixes
108 |
109 | * no versions so packages arent published, tweak data ([ea30443](https://github.com/caldera-digital/platform/commit/ea30443))
110 |
111 |
112 | ### :sparkles: Features
113 |
114 | * nav, logout, all pages, theming, normalize, match versions ([cb90f0e](https://github.com/caldera-digital/platform/commit/cb90f0e))
115 | * security rules, fix for shared, filter published packages ([172fe31](https://github.com/caldera-digital/platform/commit/172fe31))
116 |
117 |
118 |
119 |
120 |
121 |
122 | ## 0.1.1 (2019-08-29)
123 |
124 |
125 | ### :sparkles: Features
126 |
127 | * bootstrap, ecommerce stripe platform with typescript ([d9ea004](https://github.com/caldera-digital/platform/commit/d9ea004))
128 | * ecom shared, init db script, auth working client ([9306579](https://github.com/caldera-digital/platform/commit/9306579))
129 | * skeleton for front, setup back in monorepo, all running! ([a2e63fc](https://github.com/caldera-digital/platform/commit/a2e63fc))
130 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/components/Form.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import styled, { css } from 'styled-components'
3 | import { encode, isEmpty } from '../utils/formUtils'
4 | import { media } from '@caldera-digital/theme'
5 |
6 | const COMMON_INPUT_STYLES = css`
7 | width: 100%;
8 | border: 3px solid ${props => props.theme.primaryColor};
9 | font-size: 1.5rem;
10 | padding: 5px;
11 | margin: 0.5rem auto 0;
12 | `
13 |
14 | export const StyledFormInput = styled.div`
15 | max-width: 500px;
16 | width: 500px;
17 | display: flex;
18 | flex-direction: column;
19 | margin-bottom: 1.5rem;
20 | position: relative;
21 |
22 | label {
23 | color: ${props => props.theme.grayText};
24 |
25 | span {
26 | font-style: italic;
27 | font-size: 0.8rem;
28 | }
29 |
30 | input {
31 | ${COMMON_INPUT_STYLES}
32 | }
33 |
34 | textarea {
35 | ${COMMON_INPUT_STYLES}
36 | resize: none;
37 | }
38 |
39 | ${({ fileUpload }) =>
40 | fileUpload &&
41 | css`
42 | input {
43 | border: none;
44 | font-size: 1rem;
45 | }
46 | `}
47 | }
48 |
49 | ${({ showField }) =>
50 | !showField &&
51 | css`
52 | display: none;
53 | `}
54 |
55 | ${media.forSmallMediumOnly`
56 | width: 100%;
57 | `}
58 | `
59 |
60 | export const Error = styled.span`
61 | position: absolute;
62 | top: 0;
63 | right: 0;
64 | font-size: 0.9rem;
65 | color: ${props => props.theme.errorColor};
66 | `
67 |
68 | export const Input = ({
69 | label,
70 | name,
71 | error,
72 | showField = true,
73 | showLabel = true,
74 | optional = false,
75 | onChange = () => null,
76 | onBlur = () => null,
77 | containerStyle = {},
78 | ...rest
79 | }) => {
80 | return (
81 |
82 |
83 | {showLabel && (
84 | <>
85 | {label} {optional && - Optional }
86 | >
87 | )}
88 |
89 |
96 |
97 | {error && {error} }
98 |
99 | )
100 | }
101 |
102 | export const FileUpload = ({
103 | label,
104 | name,
105 | error,
106 | showField = true,
107 | optional = false,
108 | onChange = () => null,
109 | onBlur = () => null,
110 | ...rest
111 | }) => {
112 | return (
113 |
114 | {label && (
115 |
116 | {label} {optional && - Optional }
117 |
124 |
125 | )}
126 | {error && {error} }
127 |
128 | )
129 | }
130 |
131 | export const Textarea = ({
132 | label,
133 | name,
134 | error,
135 | showField = true,
136 | optional = false,
137 | onChange = () => null,
138 | onBlur = () => null,
139 | ...rest
140 | }) => {
141 | return (
142 |
143 | {label && (
144 |
145 | {label} {optional && - Optional }
146 |
153 |
154 | )}
155 | {error && {error} }
156 |
157 | )
158 | }
159 |
160 | export const NetlifyForm = ({
161 | children,
162 | initialValues = {},
163 | validationSchema = {},
164 | onFormSubmit = () => null,
165 | formName,
166 | }) => {
167 | const [values, setValues] = useState(initialValues)
168 | const [touched, setTouched] = useState(
169 | Object.keys(values).map(key => ({
170 | [key]: false,
171 | })),
172 | )
173 |
174 | const onChange = ({ target: { name, value } }) =>
175 | setValues({ ...values, ...{ [name]: value } })
176 | const onBlur = ({ target: { name } }) =>
177 | setTouched({ ...touched, ...{ [name]: true } })
178 |
179 | const formKeys = Object.keys(values)
180 |
181 | const errors = formKeys.reduce((accu, item) => {
182 | const validate = validationSchema[item]
183 |
184 | if (validate) {
185 | const error = validate(values[item])
186 |
187 | if (error) accu[item] = error
188 | }
189 |
190 | return accu
191 | }, {})
192 | const isValid = isEmpty(errors)
193 |
194 | const handleSubmit = e => {
195 | fetch('/', {
196 | method: 'POST',
197 | headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
198 | body: encode({ 'form-name': formName, ...values }),
199 | })
200 | .then(() => onFormSubmit())
201 | // eslint-disable-next-line no-alert
202 | .catch(error => alert(error))
203 |
204 | e.preventDefault()
205 | }
206 |
207 | return children({
208 | onChange,
209 | onBlur,
210 | isValid,
211 | handleSubmit,
212 | errors,
213 | values,
214 | touched,
215 | })
216 | }
217 |
--------------------------------------------------------------------------------
/packages/nav/src/Nav.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import styled, { css } from 'styled-components'
3 | import { media } from '@caldera-digital/theme'
4 | import { Hamburger } from './Hamburger'
5 |
6 | const NavContainer = styled.div`
7 | height: ${props => props.theme.desktopHeaderHeight};
8 | background-color: ${props => props.theme.primaryColor};
9 | color: ${props => props.theme.white};
10 | display: flex;
11 | align-items: center;
12 | justify-content: space-between;
13 | padding: 0 2rem;
14 | position: relative;
15 | z-index: 100;
16 |
17 | ${media.forSmallOnly`
18 | height: ${props => props.theme.mobileHeaderHeight};
19 | padding: 0 1rem;
20 | `}
21 | `
22 |
23 | const NavOptionsContainer = styled.div`
24 | display: flex;
25 | align-items: center;
26 | justify-content: flex-end;
27 | `
28 |
29 | const NavLinkStyles = css`
30 | color: ${props => props.theme.white} !important;
31 | text-decoration: none;
32 | margin-right: 1rem;
33 | position: relative;
34 | cursor: pointer;
35 |
36 | &:last-child {
37 | margin-right: 0;
38 | }
39 |
40 | /* &:before, */
41 | &:after {
42 | content: '';
43 | position: absolute;
44 | bottom: -7px;
45 | width: 0px;
46 | height: 3px;
47 | margin: 5px 0 0;
48 | transition: all 0.4s ease-in-out;
49 | opacity: 0;
50 | left: 0;
51 | }
52 |
53 | &:hover {
54 | &:after {
55 | opacity: 1;
56 | background-color: ${props => props.theme.white};
57 | width: 100%;
58 | }
59 | }
60 |
61 | &.selected {
62 | &:after {
63 | opacity: 1;
64 | background-color: ${props => props.theme.white};
65 | width: 100%;
66 | }
67 | }
68 |
69 | ${media.forSmallOnly`
70 | color: ${props => props.theme.defaultFontColor} !important;
71 | margin-bottom: 0.25rem;
72 | padding: .75rem;
73 | margin: 0;
74 | font-size: ${props => props.theme.defaultFontSize};
75 |
76 | &.selected {
77 | font-weight: bold;
78 | }
79 |
80 | &:after {
81 | display: none !important;
82 | }
83 | `}
84 | `
85 |
86 | const RoutesContainer = styled.div`
87 | display: flex;
88 | align-items: center;
89 |
90 | ${media.forSmallOnly`
91 | position: absolute;
92 | height: calc(100vh - ${({ theme }) => theme.mobileHeaderHeight});
93 | top: ${({ theme }) => theme.mobileHeaderHeight};
94 | left: 0;
95 | background-color: ${({ theme }) => theme.white};
96 | width: 100%;
97 | display: ${({ open }) => (open ? 'flex' : 'none')};
98 | flex-direction: column;
99 | padding: 1rem;
100 | z-index: 20;
101 | `}
102 | `
103 |
104 | const createRouteLink = as => styled(as)`
105 | ${NavLinkStyles};
106 | `
107 |
108 | export const NavComponent = ({
109 | routes = [],
110 | className = '',
111 | containerStyle = {},
112 | navOptionsStyle = {},
113 | navOptionsClassName = '',
114 | hamburgerStyle = {},
115 | routesContainerStyle = {},
116 | routesContainerClassName = '',
117 | renderLeftSection = () => null,
118 | hamburgerOpen: hamburgerOpenProp = false,
119 | onHamburgerClicked,
120 | hamburgerColor,
121 | }) => {
122 | const [hamburgerOpen, setHamburgerOpen] = React.useState(hamburgerOpenProp)
123 |
124 | useEffect(() => {
125 | setHamburgerOpen(hamburgerOpenProp)
126 | }, [hamburgerOpenProp])
127 |
128 | return (
129 |
130 | {renderLeftSection()}
131 |
132 |
136 |
139 | onHamburgerClicked
140 | ? onHamburgerClicked(hamburgerOpen)
141 | : setHamburgerOpen(!hamburgerOpen)
142 | }
143 | hamburgerColor={hamburgerColor}
144 | style={hamburgerStyle}
145 | />
146 |
151 | {routes.map(item => {
152 | const {
153 | route,
154 | text,
155 | as = 'a',
156 | render,
157 | selected = false,
158 | renderLinkContent,
159 | onClick = () => null,
160 | className = '',
161 | ...rest
162 | } = item
163 |
164 | if (render) render(item)
165 | // The controls what the link renders as so it works with Reach, React Router, and normal
166 | const RouteLink = createRouteLink(as)
167 |
168 | return (
169 | {
174 | setHamburgerOpen(false)
175 |
176 | onClick({ route, text, ...rest })
177 | }}
178 | {...rest}
179 | >
180 | {renderLinkContent ? renderLinkContent() : text}
181 |
182 | )
183 | })}
184 |
185 |
186 |
187 | )
188 | }
189 |
190 | export const Nav = props =>
191 |
--------------------------------------------------------------------------------
/projects/ecommerce-stripe-client/src/serviceWorker.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
2 | // This optional code is used to register a service worker.
3 | // register() is not called by default.
4 |
5 | // This lets the app load faster on subsequent visits in production, and gives
6 | // it offline capabilities. However, it also means that developers (and users)
7 | // will only see deployed updates on subsequent visits to a page, after all the
8 | // existing tabs open on the page have been closed, since previously cached
9 | // resources are updated in the background.
10 |
11 | // To learn more about the benefits of this model and instructions on how to
12 | // opt-in, read https://bit.ly/CRA-PWA
13 |
14 | const isLocalhost = Boolean(
15 | window.location.hostname === 'localhost' ||
16 | // [::1] is the IPv6 localhost address.
17 | window.location.hostname === '[::1]' ||
18 | // 127.0.0.1/8 is considered localhost for IPv4.
19 | window.location.hostname.match(
20 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
21 | ),
22 | )
23 |
24 | type Config = {
25 | onSuccess?: (registration: ServiceWorkerRegistration) => void
26 | onUpdate?: (registration: ServiceWorkerRegistration) => void
27 | }
28 |
29 | export function register(config?: Config) {
30 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
31 | // The URL constructor is available in all browsers that support SW.
32 | const publicUrl = new URL(
33 | (process as { env: { [key: string]: string } }).env.PUBLIC_URL,
34 | window.location.href,
35 | )
36 | if (publicUrl.origin !== window.location.origin) {
37 | // Our service worker won't work if PUBLIC_URL is on a different origin
38 | // from what our page is served on. This might happen if a CDN is used to
39 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
40 | return
41 | }
42 |
43 | window.addEventListener('load', () => {
44 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
45 |
46 | if (isLocalhost) {
47 | // This is running on localhost. Let's check if a service worker still exists or not.
48 | checkValidServiceWorker(swUrl, config)
49 |
50 | // Add some additional logging to localhost, pointing developers to the
51 | // service worker/PWA documentation.
52 | navigator.serviceWorker.ready.then(() => {
53 | console.log(
54 | 'This web app is being served cache-first by a service ' +
55 | 'worker. To learn more, visit https://bit.ly/CRA-PWA',
56 | )
57 | })
58 | } else {
59 | // Is not localhost. Just register service worker
60 | // eslint-disable-next-line @typescript-eslint/no-use-before-define
61 | registerValidSW(swUrl, config)
62 | }
63 | })
64 | }
65 | }
66 |
67 | function registerValidSW(swUrl: string, config?: Config) {
68 | navigator.serviceWorker
69 | .register(swUrl)
70 | .then(registration => {
71 | registration.onupdatefound = () => {
72 | const installingWorker = registration.installing
73 | if (installingWorker == null) {
74 | return
75 | }
76 | installingWorker.onstatechange = () => {
77 | if (installingWorker.state === 'installed') {
78 | if (navigator.serviceWorker.controller) {
79 | // At this point, the updated precached content has been fetched,
80 | // but the previous service worker will still serve the older
81 | // content until all client tabs are closed.
82 | console.log(
83 | 'New content is available and will be used when all ' +
84 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
85 | )
86 |
87 | // Execute callback
88 | if (config && config.onUpdate) {
89 | config.onUpdate(registration)
90 | }
91 | } else {
92 | // At this point, everything has been precached.
93 | // It's the perfect time to display a
94 | // "Content is cached for offline use." message.
95 | console.log('Content is cached for offline use.')
96 |
97 | // Execute callback
98 | if (config && config.onSuccess) {
99 | config.onSuccess(registration)
100 | }
101 | }
102 | }
103 | }
104 | }
105 | })
106 | .catch(error => {
107 | console.error('Error during service worker registration:', error)
108 | })
109 | }
110 |
111 | function checkValidServiceWorker(swUrl: string, config?: Config) {
112 | // Check if the service worker can be found. If it can't reload the page.
113 | fetch(swUrl)
114 | .then(response => {
115 | // Ensure service worker exists, and that we really are getting a JS file.
116 | const contentType = response.headers.get('content-type')
117 | if (
118 | response.status === 404 ||
119 | (contentType != null && contentType.indexOf('javascript') === -1)
120 | ) {
121 | // No service worker found. Probably a different app. Reload the page.
122 | navigator.serviceWorker.ready.then(registration => {
123 | registration.unregister().then(() => {
124 | window.location.reload()
125 | })
126 | })
127 | } else {
128 | // Service worker found. Proceed as normal.
129 | registerValidSW(swUrl, config)
130 | }
131 | })
132 | .catch(() => {
133 | console.log(
134 | 'No internet connection found. App is running in offline mode.',
135 | )
136 | })
137 | }
138 |
139 | export function unregister() {
140 | if ('serviceWorker' in navigator) {
141 | navigator.serviceWorker.ready.then(registration => {
142 | registration.unregister()
143 | })
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/projects/caldera-www/src/assets/svgs/analytics.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------