diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..31a9930 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*.{html,css,js,ts,jsx,tsx,json}] +charset = utf-8 +indent_style = tab +indent_size = 2 +quote_type= single \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4ca0343 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +VITE_GRAPHQL_SUPPORT_API=https://example.com/graphql +VITE_PAYMENT_API=https://example.com/payment/api +VITE_GRAPHQL_SUPPORT_SUBSCRIPTIONS_API=https://example.com/graphql +VITE_GRAPHQL_API=https://example.com/graphql +VITE_STRIPE_PUBLIC_KEY=STRIPE_PUBLIC_KEY +VITE_CLOUDINARY_URL=CLOUDINARY_URL \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..82a9a73 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +.eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..ac9efb0 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,65 @@ +module.exports = { + extends: [ + 'airbnb-typescript', + 'airbnb/hooks', + 'plugin:jest/recommended', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/recommended' + ], + plugins: ['react', '@typescript-eslint', 'jest', 'prettier'], + env: { + browser: true, + es6: true, + jest: true, + }, + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', + }, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 2018, + sourceType: 'module', + project: './tsconfig.json', + }, + rules: { + 'no-console': 0, + 'no-nested-ternary': 'off', + 'no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': [ + 'warn', + { allowShortCircuit: true, allowTernary: true }, + ], + '@typescript-eslint/ban-ts-comment': 0, + 'react-hooks/exhaustive-deps': 1, + 'import/no-cycle': 'off', + 'react/jsx-props-no-spreading': 'off', + 'react/require-default-props': 0, + 'import/prefer-default-export': 'off', + 'import/no-extraneous-dependencies': 0, + 'no-prototype-builtins': 'off', + 'no-plusplus': 'off', + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-non-null-asserted-optional-chain': 0, + '@typescript-eslint/no-non-null-assertion': 0, + 'react/prop-types': 'off', + 'react/react-in-jsx-scope': 'off', + 'react/self-closing-comp': 0, + 'react/no-array-index-key': 0, + '@typescript-eslint/camelcase': 'off', + '@typescript-eslint/explicit-function-return-type': 0, + '@typescript-eslint/explicit-module-boundary-types': 0, + '@typescript-eslint/no-explicit-any': 0, + 'linebreak-style': 'off', + 'prettier/prettier': [ + 'error', + { + endOfLine: 'auto', + }, + ], + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c5b47ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# development +/codegen-support.ts +/codegen-main.yml + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..16ad5a2 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "singleQuote": true, + "jsxSingleQuote": true, + "tabWidth": 2, + "semi": true, + "arrowParens": "always", + "useTabs": false, + "endOfLine": "lf" +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..46a45a0 --- /dev/null +++ b/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + Astrobuild + + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..fa7f242 --- /dev/null +++ b/package.json @@ -0,0 +1,77 @@ +{ + "name": "astrobuild", + "version": "0.1.0", + "private": true, + "dependencies": { + "@apollo/client": "^3.7.10", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", + "@types/jest": "^29.5.0", + "@types/jwt-decode": "^3.1.0", + "@types/node": "^18.15.7", + "@types/react": "^18.0.29", + "@types/react-dom": "^18.0.11", + "@types/react-router-dom": "^5.3.3", + "@types/styled-components": "^5.1.26", + "formik": "^2.2.9", + "graphql": "^16.6.0", + "graphql-ws": "^5.13.1", + "jwt-decode": "^3.1.2", + "localforage": "^1.10.0", + "match-sorter": "^6.3.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-elastic-carousel": "^0.11.5", + "react-router-dom": "^6.9.0", + "react-to-print": "^2.14.12", + "reactflow": "^11.7.0", + "sort-by": "^1.2.0", + "styled-components": "^5.3.10", + "typescript": "^5.0.2", + "vite-plugin-svgr": "^2.4.0", + "web-vitals": "^3.3.0", + "yup": "^1.0.2" + }, + "scripts": { + "start": "vite", + "build": "vite build", + "generate:main": "graphql-codegen --config codegen-main.yml", + "lint": "yarn run eslint src --ext .ts,.tsx", + "fix": "yarn lint --fix", + "generate:support": "graphql-codegen --config codegen-support.ts" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@graphql-codegen/cli": "3.3.1", + "@graphql-codegen/client-preset": "3.0.1", + "@graphql-codegen/introspection": "3.0.1", + "@graphql-codegen/typescript": "^3.0.2", + "@graphql-codegen/typescript-operations": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", + "@vitejs/plugin-react": "^4.0.0", + "eslint-config-airbnb": "19.0.4", + "eslint-config-airbnb-typescript": "^17.0.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-import": "2.27.5", + "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jsx-a11y": "6.7.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "7.32.2", + "eslint-plugin-react-hooks": "4.6.0", + "prettier": "^2.8.7", + "vite": "^4.2.1" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..b069b88 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/logo192.png b/public/logo192.png new file mode 100644 index 0000000..fc44b0a Binary files /dev/null and b/public/logo192.png differ diff --git a/public/logo512.png b/public/logo512.png new file mode 100644 index 0000000..a4e47a6 Binary files /dev/null and b/public/logo512.png differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..0917687 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,352 @@ +import jwtDecode from 'jwt-decode'; +import { useEffect } from 'react'; +import { Routes, Route, Navigate } from 'react-router-dom'; +import { useLazyQuery, useReactiveVar } from '@apollo/client'; +import { Protected, Public, Navbar, Sidebar, Spinner } from './components'; +import { roleVar, tokenVar, userVar } from './graphql/state'; +import { + AdditionalInfo, + ForgotPassword, + Login, + RecoverAccount, + Signup, + Project, + Users, + Settings, + UserSettings, + CreateUser, + Template, + Feature, + Category, + Prototype, + AddCategory, + AddFeature, + AddTemplate, + CategorySettings, + FeatureSettings, + TemplateSettings, + AddProject, + UpdateProject, + Support, +} from './pages'; +import { GetUserByIdQuery, GetUserByIdQueryVariables } from './graphql/types'; +import { GET_USER_BY_ID } from './graphql/auth.api'; + +const App = () => { + const token = useReactiveVar(tokenVar); + const role = useReactiveVar(roleVar); + const currentUser = useReactiveVar(userVar); + + const [getUserById, { loading }] = useLazyQuery< + GetUserByIdQuery, + GetUserByIdQueryVariables + >(GET_USER_BY_ID, { + onCompleted({ getUserById: user }) { + userVar(user); + switch (user.role) { + case 'Client': + roleVar('client'); + break; + case 'ProductOwner': + roleVar('productOwner'); + break; + case 'Developer': + roleVar('developer'); + break; + case 'Admin': + roleVar('admin'); + break; + default: + break; + } + }, + }); + + useEffect(() => { + const localStorageToken = localStorage.getItem('token'); + + if (localStorageToken) { + const { id } = jwtDecode<{ id: string; role: string }>(localStorageToken); + + getUserById({ variables: { id } }); + tokenVar(localStorageToken); + } + }, []); + + return !loading ? ( + <> + {token && currentUser?.firstName && ( + <> + + + + )} + + + {role !== 'admin' ? ( + + ) : ( + + )} + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + +