Merge pull request #1 from hazemKrimi/structure-updates

Project updates
This commit is contained in:
Hazem Krimi
2023-05-06 18:23:18 +01:00
committed by GitHub
68 changed files with 5967 additions and 13406 deletions
+6
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
.eslintrc.js
+1 -12
View File
@@ -5,6 +5,7 @@ module.exports = {
'plugin:jest/recommended',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/recommended'
],
plugins: ['react', '@typescript-eslint', 'jest', 'prettier'],
env: {
@@ -54,18 +55,6 @@ module.exports = {
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-explicit-any': 0,
'linebreak-style': 'off',
'jsx-a11y/label-has-associated-control': [
'error',
{
labelComponents: [],
labelAttributes: [],
controlComponents: [],
assert: 'either',
depth: 25,
},
],
'jsx-a11y/control-has-associated-label': 0,
'jsx-a11y/anchor-is-valid': 0,
'prettier/prettier': [
'error',
{
-1
View File
@@ -1 +0,0 @@
describe('Alert test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Avatar test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Box test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Button test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('CheckBox test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Input test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Link test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Modal test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Modal test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Search test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Spinner test suite', () => {});
-1
View File
@@ -1 +0,0 @@
describe('Text test suite', () => {});
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using vite"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100;300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<title>Astrobuild</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="app"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
+48 -43
View File
@@ -3,40 +3,43 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@apollo/client": "^3.3.14",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@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": "^12.0.0",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"@types/react-router-dom": "^5.1.7",
"@types/styled-components": "^5.1.9",
"formik": "^2.2.6",
"graphql": "^15.5.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",
"jwt-decode": "^3.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.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-flow-renderer": "^9.6.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"react-to-print": "^2.12.6",
"styled-components": "^5.2.3",
"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",
"subscriptions-transport-ws": "^0.9.19",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1",
"yup": "^0.32.9"
"typescript": "^5.0.2",
"vite-plugin-svgr": "^2.4.0",
"web-vitals": "^3.3.0",
"yup": "^1.0.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "vite",
"build": "vite build",
"generate-main": "graphql-codegen --config codegen-main.yml",
"generate-support": "graphql-codegen --config codegen-support.yml"
"generate-support": "graphql-codegen --config codegen-support.yml",
"lint": "yarn run eslint src --ext .ts,.tsx",
"fix": "yarn lint --fix"
},
"browserslist": {
"production": [
@@ -51,21 +54,23 @@
]
},
"devDependencies": {
"@graphql-codegen/cli": "^1.21.3",
"@graphql-codegen/introspection": "^1.18.2",
"@graphql-codegen/typescript": "^1.22.0",
"@graphql-codegen/typescript-operations": "^1.17.16",
"@typescript-eslint/eslint-plugin": "^4.21.0",
"@typescript-eslint/parser": "^4.21.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jest": "^24.3.4",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-react": "7.21.5",
"eslint-plugin-react-hooks": "1.7.0",
"prettier": "^2.2.1"
"@graphql-codegen/cli": "^3.2.2",
"@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"
}
}
-49
View File
@@ -1,49 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100;300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<title>Astrobuild</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
+235 -75
View File
@@ -1,10 +1,10 @@
import jwtDecode from 'jwt-decode';
import { useEffect } from 'react';
import { Redirect, Switch } from 'react-router-dom';
import { Routes, Route, Navigate } from 'react-router-dom';
import { useLazyQuery, useReactiveVar } from '@apollo/client';
import {
ProtectedRoute,
AuthRoute,
Protected,
Public,
Navbar,
Sidebar,
Spinner,
@@ -78,8 +78,6 @@ const App = () => {
getUserById({ variables: { id } });
tokenVar(localStorageToken);
}
// eslint-disable-next-line
}, []);
return !loading ? (
@@ -90,111 +88,273 @@ const App = () => {
<Sidebar />
</>
)}
<Switch>
<ProtectedRoute path='/' exact>
<Routes>
<Route path='/' element={
<Protected>
{role !== 'admin' ? (
<Redirect to='/project' />
<Navigate to='/project' />
) : (
<Redirect to='/clients' />
<Navigate to='/clients' />
)}
</ProtectedRoute>
<ProtectedRoute path='/project' exact>
</Protected>
} />
<Route
path='/project'
element={
<Protected>
<Project />
</ProtectedRoute>
<ProtectedRoute path='/project/:id' exact>
</Protected>
}
/>
<Route
path='/project/:id'
element={
<Protected>
<Project />
</ProtectedRoute>
<ProtectedRoute path='/payments/:id' exact>
</Protected>
}
/>
<Route
path='/payments/:id'
element={
<Protected>
<Payments />
</ProtectedRoute>
<ProtectedRoute path='/add-project' exact>
</Protected>
}
/>
<Route
path='/add-project'
element={
<Protected>
<AddProject />
</ProtectedRoute>
<ProtectedRoute path='/project-settings/:id' exact>
</Protected>
}
/>
<Route
path='/project-settings/:id'
element={
<Protected>
<UpdateProject />
</ProtectedRoute>
<ProtectedRoute path='/support-messaging/:project' exact>
</Protected>
}
/>
<Route
path='/support-messaging/:project'
element={
<Protected>
<SupportMessaging />
</ProtectedRoute>
<ProtectedRoute path='/support-messaging/:project/:id' exact>
</Protected>
}
/>
<Route
path='/support-messaging/:project/:id'
element={
<Protected>
<SupportMessaging />
</ProtectedRoute>
<ProtectedRoute path='/template' exact>
</Protected>
}
/>
<Route
path='/template'
element={
<Protected>
<Template />
</ProtectedRoute>
<ProtectedRoute path='/template/:id' exact>
</Protected>
}
/>
<Route
path='/template/:id'
element={
<Protected>
<Template />
</ProtectedRoute>
<ProtectedRoute path='/add-template' exact>
</Protected>
}
/>
<Route
path='/add-template'
element={
<Protected>
<AddTemplate />
</ProtectedRoute>
<ProtectedRoute path='/template-settings/:id' exact>
</Protected>
}
/>
<Route
path='/template-settings/:id'
element={
<Protected>
<TemplateSettings />
</ProtectedRoute>
<ProtectedRoute path='/add-template' exact>
</Protected>
}
/>
<Route
path='/add-template'
element={
<Protected>
<AddTemplate />
</ProtectedRoute>
<ProtectedRoute path='/feature' exact>
</Protected>
}
/>
<Route
path='/feature'
element={
<Protected>
<Feature />
</ProtectedRoute>
<ProtectedRoute path='/feature/:id' exact>
</Protected>
}
/>
<Route
path='/feature/:id'
element={
<Protected>
<Feature />
</ProtectedRoute>
<ProtectedRoute path='/add-feature' exact>
</Protected>
}
/>
<Route
path='/add-feature'
element={
<Protected>
<AddFeature />
</ProtectedRoute>
<ProtectedRoute path='/feature-settings/:id' exact>
</Protected>
}
/>
<Route
path='/feature-settings/:id'
element={
<Protected>
<FeatureSettings />
</ProtectedRoute>
<ProtectedRoute path='/category' exact>
</Protected>
}
/>
<Route
path='/category'
element={
<Protected>
<Category />
</ProtectedRoute>
<ProtectedRoute path='/category/:id' exact>
</Protected>
}
/>
<Route
path='/category/:id'
element={
<Protected>
<Category />
</ProtectedRoute>
<ProtectedRoute path='/add-category' exact>
</Protected>
}
/>
<Route
path='/add-category'
element={
<Protected>
<AddCategory />
</ProtectedRoute>
<ProtectedRoute path='/category-settings/:id' exact>
</Protected>
}
/>
<Route
path='/category-settings/:id'
element={
<Protected>
<CategorySettings />
</ProtectedRoute>
<ProtectedRoute path='/prototype/:id' exact>
</Protected>
}
/>
<Route
path='/prototype/:id'
element={
<Protected>
<Prototype />
</ProtectedRoute>
<ProtectedRoute path='/clients' exact>
</Protected>
}
/>
<Route
path='/clients'
element={
<Protected>
<Users />
</ProtectedRoute>
<ProtectedRoute path='/product-owners' exact>
</Protected>
}
/>
<Route
path='/product-owners'
element={
<Protected>
<Users />
</ProtectedRoute>
<ProtectedRoute path='/developers' exact>
</Protected>
}
/>
<Route
path='/developers'
element={
<Protected>
<Users />
</ProtectedRoute>
<ProtectedRoute path='/create-user/:role' exact>
</Protected>
}
/>
<Route
path='/create-user/:role'
element={
<Protected>
<CreateUser />
</ProtectedRoute>
<ProtectedRoute path='/user-settings/:id' exact>
</Protected>
}
/>
<Route
path='/user-settings/:id'
element={
<Protected>
<UserSettings />
</ProtectedRoute>
<ProtectedRoute path='/settings' exact>
</Protected>
}
/>
<Route
path='/settings'
element={
<Protected>
<Settings />
</ProtectedRoute>
<AuthRoute path='/login' exact>
</Protected>
}
/>
<Route
path='/login'
element={
<Public>
<Login />
</AuthRoute>
<AuthRoute path='/signup' exact>
</Public>
}
/>
<Route
path='/signup'
element={
<Public>
<Signup />
</AuthRoute>
<ProtectedRoute path='/additional-info' exact>
</Public>
}
/>
<Route
path='/additional-info'
element={
<Protected>
<AdditionalInfo />
</ProtectedRoute>
<AuthRoute path='/forgot-password' exact>
</Protected>
}
/>
<Route
path='/forgot-password'
element={
<Public>
<ForgotPassword />
</AuthRoute>
<AuthRoute path='/recover-account' exact>
</Public>
}
/>
<Route
path='/recover-account'
element={
<Public>
<RecoverAccount />
</AuthRoute>
</Switch>
</Public>
}
/>
</Routes>
</>
) : (
<Spinner fullScreen color={role || 'client'} />
-13
View File
@@ -1,13 +0,0 @@
import { useReactiveVar } from '@apollo/client';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { tokenVar } from '../../graphql/state';
const AuthRoute: React.FC<RouteProps> = ({ children, ...rest }) => {
const token = useReactiveVar(tokenVar);
return (
<Route {...rest} render={() => (!token ? children : <Redirect to='/' />)} />
);
};
export default AuthRoute;
+2 -2
View File
@@ -6,8 +6,8 @@ type ButtonProps = {
size?: 'small' | 'big';
variant?: 'primary-action' | 'secondary-action' | 'outlined' | 'text';
type?: 'submit' | 'button' | 'reset';
iconLeft?: React.SVGProps<SVGSVGElement>;
iconRight?: React.SVGProps<SVGSVGElement>;
iconLeft?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
iconRight?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
fullWidth?: boolean;
loading?: boolean;
disabled?: boolean;
+2 -2
View File
@@ -4,8 +4,8 @@ type WrapperProps = {
color: 'client' | 'productOwner' | 'developer' | 'admin' | 'error';
size?: 'small' | 'big';
variant?: 'primary-action' | 'secondary-action' | 'outlined' | 'text';
iconLeft?: React.SVGProps<SVGSVGElement>;
iconRight?: React.SVGProps<SVGSVGElement>;
iconLeft?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
iconRight?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
load?: boolean;
disabled?: boolean;
fullWidth?: boolean;
+12 -20
View File
@@ -10,46 +10,38 @@ type ContextMenuProps = {
const ContextMenu = ({ items, component, className }: ContextMenuProps) => {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
const parentComponentRef = useRef<HTMLDivElement>();
useEffect(() => {
const wrapper = ref.current;
parentComponentRef.current = document.querySelector(`#${component}`) as HTMLDivElement;
const openMenu = () => setOpen(true);
const closeMenu = () => setOpen(false);
(document.querySelector(`#${component}`) as HTMLElement)?.addEventListener(
parentComponentRef.current?.addEventListener(
'mouseenter',
openMenu
);
ref.current?.addEventListener('mouseleave', closeMenu);
parentComponentRef.current?.addEventListener(
'mouseleave',
closeMenu
);
return () => {
(document.querySelector(
`#${component}`
) as HTMLElement)?.removeEventListener('mouseenter', openMenu);
wrapper?.removeEventListener('mouseleave', closeMenu);
parentComponentRef.current?.removeEventListener('mouseenter', openMenu);
parentComponentRef.current?.removeEventListener('mouseleave', closeMenu);
};
// eslint-disable-next-line
}, [ref.current]);
}, []);
return (
<Wrapper
ref={ref}
className={className}
top={
(document.querySelector(`#${component}`) as HTMLElement)?.offsetTop + 30
}
left={
(document.querySelector(`#${component}`) as HTMLElement)?.offsetLeft +
10
}
top={(parentComponentRef.current as HTMLDivElement)?.getBoundingClientRect().top + 30}
left={(parentComponentRef.current as HTMLDivElement)?.getBoundingClientRect().left + 10}
>
{open && (
<ul>
{items.map(({ label, action }) => (
// eslint-disable-next-line
<li
onClick={() => {
if (action) {
+11 -4
View File
@@ -1,16 +1,21 @@
import { Handle, Position } from 'reactflow';
import { Box, Text } from '..';
import { FeatureOutput } from '../../graphql/types';
type FrontendFeatureCardProps = {
feature: FeatureOutput;
data: FeatureOutput;
isConnectable?: boolean;
className?: string;
};
const FrontendFeatureCard = ({
feature,
data,
isConnectable = false,
className,
}: FrontendFeatureCardProps) => {
return (
<>
<Handle type="target" position={Position.Top} isConnectable={isConnectable} />
<Box
className={className}
padding='10px'
@@ -27,7 +32,7 @@ const FrontendFeatureCard = ({
<Box display='flex' flexDirection='row' alignItems='center'>
<Box flexGrow='1'>
<Text variant='title' weight='bold'>
{feature.name}
{data.name}
</Text>
</Box>
</Box>
@@ -38,7 +43,7 @@ const FrontendFeatureCard = ({
justifyContent='space-between'
padding='5px 20px'
>
{feature.wireframes?.map((wireframe) => (
{data.wireframes?.map((wireframe) => (
<img
src={wireframe.src}
alt={wireframe.name}
@@ -48,6 +53,8 @@ const FrontendFeatureCard = ({
))}
</Box>
</Box>
<Handle type="source" position={Position.Bottom} isConnectable={isConnectable} />
</>
);
};
+1 -1
View File
@@ -3,7 +3,7 @@ import { Wrapper } from './styles';
type IconButtonProps = {
color?: 'client' | 'productOwner' | 'developer' | 'admin';
size?: 'small' | 'medium' | 'big';
icon?: React.SVGProps<SVGSVGElement>;
icon?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
onClick: () => void;
};
+1 -1
View File
@@ -3,7 +3,7 @@ import styled, { css } from 'styled-components';
type WrapperProps = {
color?: 'client' | 'productOwner' | 'developer' | 'admin';
size?: 'small' | 'medium' | 'big';
icon?: React.SVGProps<SVGSVGElement>;
icon?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
};
export const Wrapper = styled.button<WrapperProps>`
+1 -1
View File
@@ -18,7 +18,7 @@ type LinkProps = {
| string;
selected?: boolean;
className?: string;
iconLeft?: React.SVGProps<SVGSVGElement>;
iconLeft?: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
onClick?: () => void;
target?: '_self' | '_blank';
};
+14 -21
View File
@@ -5,7 +5,7 @@ import { Text } from '..';
type MenuProps = {
className?: string;
items: Array<{
icon: React.SVGProps<SVGSVGElement>;
icon: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
avoid?: boolean;
label: string;
action?: () => void;
@@ -15,45 +15,38 @@ type MenuProps = {
const Menu = ({ items, component, className }: MenuProps) => {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const wrapper = ref.current;
const componentRef = useRef<HTMLDivElement>(null);
const parentComponentRef = useRef<HTMLDivElement>();
const openMenu = () => setOpen(true);
const closeMenu = () => setOpen(false);
(document.querySelector(`#${component}`) as HTMLElement)?.addEventListener(
'mouseenter',
openMenu
);
ref.current?.addEventListener('mouseleave', closeMenu);
useEffect(() => {
parentComponentRef.current = document.querySelector(`#${component}`) as HTMLDivElement;
parentComponentRef.current?.addEventListener('mouseenter', openMenu);
componentRef.current?.addEventListener('mouseleave', closeMenu);
return () => {
(document.querySelector(
`#${component}`
) as HTMLElement)?.removeEventListener('mouseenter', openMenu);
wrapper?.addEventListener('mouseleave', closeMenu);
parentComponentRef.current?.removeEventListener('mouseenter', openMenu);
componentRef.current?.removeEventListener('mouseleave', closeMenu);
};
// eslint-disable-next-line
}, [ref.current]);
}, []);
return (
<Wrapper
ref={ref}
ref={componentRef}
className={className}
top={
(document.querySelector(`#${component}`) as HTMLElement)?.offsetTop + 30
(parentComponentRef.current as HTMLDivElement)?.getBoundingClientRect().top + 30
}
left={
(document.querySelector(`#${component}`) as HTMLElement)?.offsetLeft
(parentComponentRef.current as HTMLDivElement)?.getBoundingClientRect()?.left
}
>
{open && (
<ul>
{items.map(({ icon, label, avoid, action }) => (
// eslint-disable-next-line
<li
onClick={() => {
if (action) {
+4 -6
View File
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { useHistory, useLocation } from 'react-router';
import { useNavigate, useLocation } from 'react-router';
import { useReactiveVar } from '@apollo/client';
import { roleVar } from '../../graphql/state';
import { Box, Button, Text } from '..';
@@ -20,7 +20,7 @@ type MessagingSidebarProps = {
const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
const role = useReactiveVar(roleVar);
const location = useLocation();
const history = useHistory();
const navigate = useNavigate();
const [projectThreads, setProjectThreads] = useState<Array<ThreadObject>>();
useEffect(() => {
@@ -65,9 +65,7 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
iconLeft={<Add />}
onClick={() => {
onClose();
history.push(
`/support-messaging/${location.pathname.split('/')[2]}`
);
navigate(`/support-messaging/${location.pathname.split('/')[2]}`);
}}
/>
</Box>
@@ -87,7 +85,7 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
borderRadius='10px'
onClick={() => {
onClose();
history.push(
navigate(
`/support-messaging/${location.pathname.split('/')[2]}/${
thread.id
}`
+4 -4
View File
@@ -1,5 +1,5 @@
import { useReactiveVar } from '@apollo/client';
import { useHistory, useLocation } from 'react-router';
import { useNavigate, useLocation } from 'react-router';
import { roleVar, tokenVar, userVar } from '../../graphql/state';
import { Wrapper } from './styles';
import { Avatar, Link, Menu, Text } from '..';
@@ -8,7 +8,7 @@ import { Settings, Logout, Logo } from '../../assets';
const Navbar = () => {
const user = useReactiveVar(userVar);
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
return (
@@ -151,7 +151,7 @@ const Navbar = () => {
{
icon: <Settings />,
label: 'Settings',
action: () => history.push('/settings'),
action: () => navigate('/settings'),
},
{
icon: <Logout />,
@@ -159,7 +159,7 @@ const Navbar = () => {
action: () => {
tokenVar(undefined);
localStorage.removeItem('token');
history.push('/login');
navigate('/login');
},
avoid: true,
},
+19
View File
@@ -0,0 +1,19 @@
import { useReactiveVar } from '@apollo/client';
import { Navigate } from 'react-router-dom';
import { tokenVar } from '../../graphql/state';
type Props = {
children: React.ReactNode;
};
const Protected = ({ children }: Props) => {
const token = useReactiveVar(tokenVar);
return (
<>
{token ? children : <Navigate to='/login' />}
</>
);
};
export default Protected;
-16
View File
@@ -1,16 +0,0 @@
import { useReactiveVar } from '@apollo/client';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { tokenVar } from '../../graphql/state';
const ProtectedRoute: React.FC<RouteProps> = ({ children, ...rest }) => {
const token = useReactiveVar(tokenVar);
return (
<Route
{...rest}
render={() => (token ? children : <Redirect to='/login' />)}
/>
);
};
export default ProtectedRoute;
+19
View File
@@ -0,0 +1,19 @@
import { useReactiveVar } from '@apollo/client';
import { Navigate } from 'react-router-dom';
import { tokenVar } from '../../graphql/state';
type Props = {
children: React.ReactNode;
};
const Public = ({ children }: Props) => {
const token = useReactiveVar(tokenVar);
return (
<>
{!token ? children : <Navigate to='/' />}
</>
);
};
export default Public;
+1 -1
View File
@@ -1,7 +1,7 @@
import { Wrapper } from './styles';
type SectionSelectorProps = {
icon: React.SVGProps<SVGSVGElement>;
icon: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
text: string;
color: 'client' | 'productOwner' | 'developer' | 'admin';
selected?: boolean;
+1 -1
View File
@@ -1,7 +1,7 @@
import styled, { css } from 'styled-components';
type WrapperProps = {
icon: React.SVGProps<SVGSVGElement>;
icon: React.FunctionComponentElement<React.SVGProps<SVGSVGElement>>;
color: 'client' | 'productOwner' | 'developer' | 'admin';
selected: boolean;
disabled: boolean;
+12 -13
View File
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { useHistory, useLocation } from 'react-router';
import { useNavigate, useLocation } from 'react-router';
import { useLazyQuery, useReactiveVar } from '@apollo/client';
import { roleVar, userVar } from '../../graphql/state';
import {
@@ -39,14 +39,13 @@ const Sidebar = () => {
const role = useReactiveVar(roleVar);
const currentUser = useReactiveVar(userVar);
const location = useLocation();
const history = useHistory();
const navigate = useNavigate();
const [projects, setProjects] = useState<Array<ProjectOutput>>();
const [templates, setTemplates] = useState<Array<TemplateOutput>>();
const [features, setFeatures] = useState<Array<FeatureOutput>>();
const [categories, setCategories] = useState<Array<CategoryOutput>>();
const [messagingSidebarOpen, setMessagingSidebarOpen] = useState<boolean>(
false
);
const [messagingSidebarOpen, setMessagingSidebarOpen] =
useState<boolean>(false);
const [getProjectsByClientId] = useLazyQuery<
GetAllProjectsByClientIdQuery,
@@ -143,7 +142,7 @@ const Sidebar = () => {
location.pathname
)}
text={project.name[0]}
onClick={() => history.push(`/project/${project.id}`)}
onClick={() => navigate(`/project/${project.id}`)}
/>
</div>
<ContextMenu
@@ -163,7 +162,7 @@ const Sidebar = () => {
(index === 0 && location.pathname === '/template')
}
text={template.name[0]}
onClick={() => history.push(`/template/${template.id}`)}
onClick={() => navigate(`/template/${template.id}`)}
/>
</div>
<ContextMenu
@@ -183,7 +182,7 @@ const Sidebar = () => {
(index === 0 && location.pathname === '/feature')
}
text={feature.name[0]}
onClick={() => history.push(`/feature/${feature.id}`)}
onClick={() => navigate(`/feature/${feature.id}`)}
/>
</div>
<ContextMenu
@@ -203,7 +202,7 @@ const Sidebar = () => {
(index === 0 && location.pathname === '/category')
}
text={category.name[0]}
onClick={() => history.push(`/category/${category.id}`)}
onClick={() => navigate(`/category/${category.id}`)}
/>
</div>
<ContextMenu
@@ -220,16 +219,16 @@ const Sidebar = () => {
color={role}
onClick={() => {
if (/project/i.test(location.pathname)) {
history.push('/add-project');
navigate('/add-project');
}
if (/template/i.test(location.pathname)) {
history.push('/add-template');
navigate('/add-template');
}
if (/feature/i.test(location.pathname)) {
history.push('/add-feature');
navigate('/add-feature');
}
if (/category/i.test(location.pathname)) {
history.push('/add-category');
navigate('/add-category');
}
}}
/>
+5
View File
@@ -17,4 +17,9 @@ export const Wrapper = styled.div<WrapperProps>`
grid-template-rows: 1fr auto;
justify-content: center;
padding: 55px 0px;
overflow-y: scroll;
&::-webkit-scrollbar {
width: 1px;
}
`;
+4 -4
View File
@@ -15,8 +15,8 @@ import CheckBox from './CheckBox';
import Menu from './Menu';
import Navbar from './Navbar';
import Sidebar from './Sidebar';
import ProtectedRoute from './ProtectedRoute';
import AuthRoute from './AuthRoute';
import Protected from './Protected';
import Public from './Public';
import SectionSelector from './SectionSelector';
import Modal from './Modal';
import SidebarItem from './SidebarItem';
@@ -48,8 +48,8 @@ export {
CheckBox,
Navbar,
Sidebar,
ProtectedRoute,
AuthRoute,
Protected,
Public,
SectionSelector,
Modal,
SidebarItem,
+61 -67
View File
@@ -1,7 +1,13 @@
export type Maybe<T> = T | null;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type Exact<T extends { [key: string]: unknown }> = {
[K in keyof T]: T[K];
};
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]?: Maybe<T[SubKey]>;
};
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]: Maybe<T[SubKey]>;
};
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string;
@@ -11,7 +17,6 @@ export type Scalars = {
Float: number;
};
export type MutationRoot = {
__typename?: 'MutationRoot';
createThread: Scalars['ID'];
@@ -19,27 +24,23 @@ export type MutationRoot = {
sendMsg: Scalars['ID'];
};
export type MutationRootCreateThreadArgs = {
projectId: Scalars['String'];
title: Scalars['String'];
threadDescription: Scalars['String'];
};
export type MutationRootDeleteThreadArgs = {
threadId: Scalars['String'];
};
export type MutationRootSendMsgArgs = {
threadId: Scalars['String'];
username: Scalars['String'];
msg: Scalars['String'];
};
export type MutationType =
| 'CREATED';
export type MutationType = 'CREATED';
export type QueryRoot = {
__typename?: 'QueryRoot';
@@ -48,17 +49,14 @@ export type QueryRoot = {
getThreadById: ThreadObject;
};
export type QueryRootMessagesArgs = {
threadId: Scalars['String'];
};
export type QueryRootGetProjectThreadsArgs = {
projectId: Scalars['String'];
};
export type QueryRootGetThreadByIdArgs = {
threadId: Scalars['String'];
};
@@ -75,7 +73,6 @@ export type SubscriptionRoot = {
connectStream: StreamChanged;
};
export type SubscriptionRootConnectStreamArgs = {
mutationType?: Maybe<MutationType>;
};
@@ -105,48 +102,46 @@ export type GetProjectThreadsQueryVariables = Exact<{
projectId: Scalars['String'];
}>;
export type GetProjectThreadsQuery = (
{ __typename?: 'QueryRoot' }
& { getProjectThreads: Array<(
{ __typename?: 'ThreadObject' }
& Pick<ThreadObject, 'id' | 'title' | 'threadDescription'>
& { userMessages: Array<(
{ __typename?: 'UserMessage' }
& Pick<UserMessage, 'username' | 'text'>
)> }
)> }
);
export type GetProjectThreadsQuery = { __typename?: 'QueryRoot' } & {
getProjectThreads: Array<
{ __typename?: 'ThreadObject' } & Pick<
ThreadObject,
'id' | 'title' | 'threadDescription'
> & {
userMessages: Array<
{ __typename?: 'UserMessage' } & Pick<
UserMessage,
'username' | 'text'
>
>;
}
>;
};
export type GetThreadByIdQueryVariables = Exact<{
threadId: Scalars['String'];
}>;
export type GetThreadByIdQuery = (
{ __typename?: 'QueryRoot' }
& { getThreadById: (
{ __typename?: 'ThreadObject' }
& Pick<ThreadObject, 'id' | 'title' | 'threadDescription'>
& { userMessages: Array<(
{ __typename?: 'UserMessage' }
& Pick<UserMessage, 'username' | 'text'>
)> }
) }
);
export type GetThreadByIdQuery = { __typename?: 'QueryRoot' } & {
getThreadById: { __typename?: 'ThreadObject' } & Pick<
ThreadObject,
'id' | 'title' | 'threadDescription'
> & {
userMessages: Array<
{ __typename?: 'UserMessage' } & Pick<UserMessage, 'username' | 'text'>
>;
};
};
export type MessagesQueryVariables = Exact<{
threadId: Scalars['String'];
}>;
export type MessagesQuery = (
{ __typename?: 'QueryRoot' }
& { messages: Array<(
{ __typename?: 'UserMessage' }
& Pick<UserMessage, 'username' | 'text'>
)> }
);
export type MessagesQuery = { __typename?: 'QueryRoot' } & {
messages: Array<
{ __typename?: 'UserMessage' } & Pick<UserMessage, 'username' | 'text'>
>;
};
export type CreateThreadMutationVariables = Exact<{
projectId: Scalars['String'];
@@ -154,11 +149,10 @@ export type CreateThreadMutationVariables = Exact<{
threadDescription: Scalars['String'];
}>;
export type CreateThreadMutation = (
{ __typename?: 'MutationRoot' }
& Pick<MutationRoot, 'createThread'>
);
export type CreateThreadMutation = { __typename?: 'MutationRoot' } & Pick<
MutationRoot,
'createThread'
>;
export type SendMsgMutationVariables = Exact<{
threadId: Scalars['String'];
@@ -166,25 +160,25 @@ export type SendMsgMutationVariables = Exact<{
msg: Scalars['String'];
}>;
export type SendMsgMutation = (
{ __typename?: 'MutationRoot' }
& Pick<MutationRoot, 'sendMsg'>
);
export type SendMsgMutation = { __typename?: 'MutationRoot' } & Pick<
MutationRoot,
'sendMsg'
>;
export type ConnectStreamSubscriptionVariables = Exact<{
mutationType?: Maybe<MutationType>;
}>;
export type ConnectStreamSubscription = (
{ __typename?: 'SubscriptionRoot' }
& { connectStream: (
{ __typename?: 'StreamChanged' }
& Pick<StreamChanged, 'mutationType' | 'id'>
& { userMessage?: Maybe<(
{ __typename?: 'UserMessageObject' }
& Pick<UserMessageObject, 'id' | 'username' | 'text'>
)> }
) }
);
export type ConnectStreamSubscription = { __typename?: 'SubscriptionRoot' } & {
connectStream: { __typename?: 'StreamChanged' } & Pick<
StreamChanged,
'mutationType' | 'id'
> & {
userMessage?: Maybe<
{ __typename?: 'UserMessageObject' } & Pick<
UserMessageObject,
'id' | 'username' | 'text'
>
>;
};
};
+2068 -1521
View File
File diff suppressed because it is too large Load Diff
+17 -8
View File
@@ -1,5 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import * as ReactDOMClient from 'react-dom/client';
import {
ApolloClient,
InMemoryCache,
@@ -18,15 +18,15 @@ import GlobalStyles from './GlobalStyles';
import reportWebVitals from './reportWebVitals';
const httpLinkMain = createHttpLink({
uri: process.env.REACT_APP_GRAPHQL_API,
uri: import.meta.env.VITE_GRAPHQL_API,
});
const httpLinkSupport = createHttpLink({
uri: process.env.REACT_APP_GRAPHQL_SUPPORT_API,
uri: import.meta.env.VITE_GRAPHQL_SUPPORT_API,
});
const wsLink = new WebSocketLink({
uri: `${process.env.REACT_APP_GRAPHQL_SUPPORT_SUBSCRIPTIONS_API}`,
uri: `${import.meta.env.VITE_GRAPHQL_SUPPORT_SUBSCRIPTIONS_API}`,
options: {
reconnect: true,
},
@@ -65,19 +65,28 @@ export const clientSupport = new ApolloClient({
cache: new InMemoryCache(),
});
ReactDOM.render(
let root: ReactDOMClient.Root | null = null;
document.addEventListener('DOMContentLoaded', () => {
if (!root) {
root = ReactDOMClient.createRoot(document.querySelector('#app') as HTMLElement);
root.render(
<React.StrictMode>
<ApolloProvider client={clientMain}>
{/* @ts-ignore */}
<ThemeProvider theme={theme}>
<BrowserRouter>
<App />
{/* @ts-ignore */}
<GlobalStyles />
</BrowserRouter>
</ThemeProvider>
</ApolloProvider>
</React.StrictMode>,
document.getElementById('root')
);
</React.StrictMode>
)
}
});
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
+8 -8
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory } from 'react-router';
import { Navigate, useNavigate } from 'react-router';
import { useMutation, useReactiveVar } from '@apollo/client';
import React, { useState } from 'react';
import { roleVar } from '../../graphql/state';
@@ -22,7 +22,7 @@ import {
import { ADD_CATEGORY } from '../../graphql/category.api';
const AddCategory = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const [error, setError] = useState<string>('');
@@ -32,10 +32,10 @@ const AddCategory = () => {
AddCategoryMutationVariables
>(ADD_CATEGORY, {
onCompleted({ addCategory: { id } }) {
history.push(`/category/${id}`);
navigate(`/category/${id}`);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -73,7 +73,7 @@ const AddCategory = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -144,7 +144,7 @@ const AddCategory = () => {
formData.append('upload_preset', 'xofll5kc');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
@@ -190,9 +190,9 @@ const AddCategory = () => {
</Wrapper>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+9 -9
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory } from 'react-router';
import { Navigate, useNavigate } from 'react-router';
import { useMutation, useReactiveVar } from '@apollo/client';
import React, { useState } from 'react';
import { roleVar } from '../../graphql/state';
@@ -24,7 +24,7 @@ import {
import { ADD_FEATURE } from '../../graphql/feature.api';
const AddFeature = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const [newFeature, setNewFeature] = useState<{
name: string;
@@ -62,10 +62,10 @@ const AddFeature = () => {
AddFeatureMutationVariables
>(ADD_FEATURE, {
onCompleted({ addFeature: { id } }) {
history.push(`/feature/${id}`);
navigate(`/feature/${id}`);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -129,7 +129,7 @@ const AddFeature = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -214,7 +214,7 @@ const AddFeature = () => {
const data = await (
await fetch(
`${process.env.REACT_APP_CLOUDINARY_URL}`,
`${import.meta.env.VITE_CLOUDINARY_URL}`,
{
method: 'POST',
body: formData,
@@ -428,7 +428,7 @@ const AddFeature = () => {
const data = await (
await fetch(
`${process.env.REACT_APP_CLOUDINARY_URL}`,
`${import.meta.env.VITE_CLOUDINARY_URL}`,
{
method: 'POST',
body: formData,
@@ -479,9 +479,9 @@ const AddFeature = () => {
</Wrapper>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+24 -27
View File
@@ -2,7 +2,7 @@
import Carousel, { consts } from 'react-elastic-carousel';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import { useState, useEffect } from 'react';
import { roleVar, userVar } from '../../graphql/state';
@@ -64,7 +64,7 @@ import { CREATE_USER, GET_ALL_USERS } from '../../graphql/admin.api';
import { GET_COUNTRY_CODES } from '../../graphql/auth.api';
const AddProject = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const currentUser = useReactiveVar(userVar);
const [error, setError] = useState<string>('');
@@ -86,14 +86,10 @@ const AddProject = () => {
const [chosenFeatures, setChosenFeatures] = useState<Array<FeatureOutput>>(
[]
);
const [
chosenDeliverables,
setChosenDeliverables,
] = useState<DelivrableInput>();
const [
chosenPaymentOption,
setChosenPaymentOption,
] = useState<PaymentOptionInput>();
const [chosenDeliverables, setChosenDeliverables] =
useState<DelivrableInput>();
const [chosenPaymentOption, setChosenPaymentOption] =
useState<PaymentOptionInput>();
const [chosenPlatforms, setChosenPlatforms] = useState<Array<string>>([]);
const [selectedFeature, setSelectedFeature] = useState<FeatureOutput>();
const [categories, setCategories] = useState<Array<CategoryOutput>>([]);
@@ -200,23 +196,21 @@ const AddProject = () => {
setStep('project-metadata');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
const [
addProjectProposal,
{ loading: addProjectProposalLoading },
] = useMutation<
const [addProjectProposal, { loading: addProjectProposalLoading }] =
useMutation<
AddProjectProposalMutation,
AddProjectProposalMutationVariables
>(ADD_PROJECT_PROPOSAL, {
onCompleted({ addProjectProposal: proposalData }) {
history.push(`/project/${proposalData.id}`);
navigate(`/project/${proposalData.id}`);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -226,7 +220,7 @@ const AddProject = () => {
AddProjectMutationVariables
>(ADD_PROJECT, {
onCompleted({ addProject: projectData }) {
if (role === 'client') history.push(`/project/${projectData.id}`);
if (role === 'client') navigate(`/project/${projectData.id}`);
else {
addProjectProposal({
variables: {
@@ -242,7 +236,7 @@ const AddProject = () => {
}
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -641,7 +635,7 @@ const AddProject = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -756,7 +750,7 @@ const AddProject = () => {
basicInfoForm.setFieldValue('imageSource', '');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
@@ -1055,8 +1049,9 @@ const AddProject = () => {
{
...deliverablesPlatformsForm.values
.selectedDeliverables,
specification: !deliverablesPlatformsForm.values
.selectedDeliverables.specification,
specification:
!deliverablesPlatformsForm.values.selectedDeliverables
.specification,
}
);
}}
@@ -1087,8 +1082,9 @@ const AddProject = () => {
{
...deliverablesPlatformsForm.values
.selectedDeliverables,
design: !deliverablesPlatformsForm.values
.selectedDeliverables.design,
design:
!deliverablesPlatformsForm.values.selectedDeliverables
.design,
}
);
}}
@@ -1149,8 +1145,9 @@ const AddProject = () => {
{
...deliverablesPlatformsForm.values
.selectedDeliverables,
fullBuild: !deliverablesPlatformsForm.values
.selectedDeliverables.fullBuild,
fullBuild:
!deliverablesPlatformsForm.values.selectedDeliverables
.fullBuild,
}
);
}}
+10 -11
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory } from 'react-router';
import { Navigate, useNavigate } from 'react-router';
import {
useLazyQuery,
useMutation,
@@ -38,7 +38,7 @@ import { GET_ALL_CATEGORIES } from '../../graphql/category.api';
import { GET_ALL_FEATURES } from '../../graphql/feature.api';
const AddTemplate = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const [newTemplate, setNewTemplate] = useState<TemplateInput>({
name: '',
@@ -77,9 +77,8 @@ const AddTemplate = () => {
features: [],
});
const [availableFeatures, setAvailableFeatures] = useState<
Array<FeatureOutput>
>();
const [availableFeatures, setAvailableFeatures] =
useState<Array<FeatureOutput>>();
const [selectedSection, setSelectedSection] = useState<
'general' | 'specification' | 'features'
@@ -108,10 +107,10 @@ const AddTemplate = () => {
AddTemplateMutationVariables
>(ADD_TEMPLATE, {
onCompleted({ addTemplate: { id } }) {
history.push(`/template/${id}`);
navigate(`/template/${id}`);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -275,7 +274,7 @@ const AddTemplate = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -368,7 +367,7 @@ const AddTemplate = () => {
const data = await (
await fetch(
`${process.env.REACT_APP_CLOUDINARY_URL}`,
`${import.meta.env.VITE_CLOUDINARY_URL}`,
{
method: 'POST',
body: formData,
@@ -814,9 +813,9 @@ const AddTemplate = () => {
</Wrapper>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'developer' && <Redirect to='/project' />)}
(role === 'developer' && <Navigate to='/project' />)}
</>
);
};
+4 -4
View File
@@ -1,7 +1,7 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { useMutation, useQuery, useReactiveVar } from '@apollo/client';
import {
Box,
@@ -24,7 +24,7 @@ import { GET_COUNTRY_CODES, UPDATE_USER_INFO } from '../../../graphql/auth.api';
import { userVar } from '../../../graphql/state';
const AdditionalInfo = () => {
const history = useHistory();
const navigate = useNavigate();
const [error, setError] = useState<string>('');
const currentUser = useReactiveVar(userVar);
const { data: countryCodes, loading: countryCodesLoading } = useQuery<
@@ -38,10 +38,10 @@ const AdditionalInfo = () => {
>(UPDATE_USER_INFO, {
onCompleted({ updateUserInfo: user }) {
userVar(user);
history.push('/');
navigate('/');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
+1 -1
View File
@@ -25,7 +25,7 @@ const ForgotPassword = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
+4 -4
View File
@@ -1,7 +1,7 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useMutation } from '@apollo/client';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { useState } from 'react';
import { tokenVar, roleVar, userVar } from '../../../graphql/state';
import { Login as LoginIllustration, Logo } from '../../../assets';
@@ -12,7 +12,7 @@ import { LOGIN } from '../../../graphql/auth.api';
import { LoginMutation, LoginMutationVariables } from '../../../graphql/types';
const Login = () => {
const history = useHistory();
const navigate = useNavigate();
const [error, setError] = useState<string>('');
const [login, { loading }] = useMutation<
@@ -39,10 +39,10 @@ const Login = () => {
tokenVar(token);
userVar(user);
localStorage.setItem('token', token);
history.push('/');
navigate('/');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
+4 -4
View File
@@ -2,7 +2,7 @@ import * as Yup from 'yup';
import { useMutation } from '@apollo/client';
import { useFormik } from 'formik';
import { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { Login as LoginIllustration, Logo } from '../../../assets';
import { Box, Button, Input, Text, Alert } from '../../../components';
import { CONFIRM_USER_RESET_PASSWORD } from '../../../graphql/auth.api';
@@ -15,7 +15,7 @@ import { Wrapper } from './styles';
const RecoverAccount = () => {
const params = new URLSearchParams(window.location.search);
const history = useHistory();
const navigate = useNavigate();
const [error, setError] = useState<string>('');
const [confirmResetPassword, { loading }] = useMutation<
@@ -23,10 +23,10 @@ const RecoverAccount = () => {
ConfirmUserResetPasswordMutationVariables
>(CONFIRM_USER_RESET_PASSWORD, {
onCompleted() {
history.push('/login');
navigate('/login');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
+4 -4
View File
@@ -1,7 +1,7 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { useMutation } from '@apollo/client';
import { Signup as SignupIllustration, Logo } from '../../../assets';
import { Box, Button, Input, Link, Text, Alert } from '../../../components';
@@ -15,7 +15,7 @@ import { SIGNUP } from '../../../graphql/auth.api';
import { roleVar, tokenVar, userVar } from '../../../graphql/state';
const Signup = () => {
const history = useHistory();
const navigate = useNavigate();
const [error, setError] = useState<string>('');
const [signup, { loading }] = useMutation<
@@ -27,10 +27,10 @@ const Signup = () => {
tokenVar(token);
userVar(user);
localStorage.setItem('token', token);
history.push('/additional-info');
navigate('/additional-info');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
+5 -5
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useLazyQuery, useReactiveVar } from '@apollo/client';
import { Redirect, useHistory, useParams } from 'react-router';
import { Navigate, useNavigate, useParams } from 'react-router';
import { roleVar } from '../../graphql/state';
import { Empty, Settings } from '../../assets';
import { Box, Button, Spinner, Text } from '../../components';
@@ -19,7 +19,7 @@ import {
const Category = () => {
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [category, setCategory] = useState<CategoryOutput>();
@@ -77,7 +77,7 @@ const Category = () => {
text='Settings'
iconLeft={<Settings />}
onClick={() =>
history.push(`/category-settings/${id || category.id}`)
navigate(`/category-settings/${id || category.id}`)
}
/>
</Box>
@@ -109,9 +109,9 @@ const Category = () => {
</>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+14 -15
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory, useParams } from 'react-router';
import { Navigate, useNavigate, useParams } from 'react-router';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import React, { useEffect, useState } from 'react';
import { roleVar } from '../../graphql/state';
@@ -33,7 +33,7 @@ import {
} from '../../graphql/category.api';
const CategorySettings = () => {
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const role = useReactiveVar(roleVar);
@@ -41,9 +41,8 @@ const CategorySettings = () => {
const [success, setSuccess] = useState<boolean>(false);
const [category, setCategory] = useState<CategoryOutput>();
const [deleteCategoryModal, setDeleteCategoryModal] = useState<boolean>(
false
);
const [deleteCategoryModal, setDeleteCategoryModal] =
useState<boolean>(false);
const [getCategory, { loading: categoryLoading }] = useLazyQuery<
GetCategoryByIdQuery,
@@ -65,7 +64,7 @@ const CategorySettings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -75,16 +74,16 @@ const CategorySettings = () => {
DeleteCategoryMutationVariables
>(DELETE_CATEGORY, {
onCompleted() {
history.push('/category');
navigate('/category');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
useEffect(() => {
getCategory({ variables: { id } });
getCategory({ variables: { id: id as string } });
// eslint-disable-next-line
}, [id]);
@@ -105,7 +104,7 @@ const CategorySettings = () => {
onSubmit: ({ name, description, imageName, imageSource }) => {
updateCategory({
variables: {
id,
id: id as string,
category: {
name,
description,
@@ -126,7 +125,7 @@ const CategorySettings = () => {
description='
If you delete this category you cannot recover it.'
onClose={() => setDeleteCategoryModal(false)}
onConfirm={() => deleteCategory({ variables: { id } })}
onConfirm={() => deleteCategory({ variables: { id: id as string } })}
></Modal>
)}
<Box>
@@ -134,7 +133,7 @@ const CategorySettings = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -212,7 +211,7 @@ const CategorySettings = () => {
form.setFieldValue('imageSource', '');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
@@ -273,9 +272,9 @@ const CategorySettings = () => {
</Wrapper>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+7 -7
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory, useParams } from 'react-router';
import { Navigate, useNavigate, useParams } from 'react-router';
import { useMutation, useQuery, useReactiveVar } from '@apollo/client';
import { useState } from 'react';
import { roleVar } from '../../graphql/state';
@@ -26,7 +26,7 @@ import { GET_COUNTRY_CODES } from '../../graphql/auth.api';
import { CREATE_USER, GET_ALL_USERS } from '../../graphql/admin.api';
const CreateUser = () => {
const history = useHistory();
const navigate = useNavigate();
const { role: newUserRole } = useParams<{
role: 'Client' | 'ProductOwner' | 'Developer';
}>();
@@ -62,7 +62,7 @@ const CreateUser = () => {
country: '',
zip: '',
},
role: newUserRole,
role: newUserRole!,
});
const [selectedSection, setSelectedSection] = useState<
@@ -81,10 +81,10 @@ const CreateUser = () => {
: newUserRole === 'ProductOwner'
? '/product-owners'
: '/developers';
history.push(location);
navigate(location);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
refetchQueries: [{ query: GET_ALL_USERS }],
@@ -179,7 +179,7 @@ const CreateUser = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -471,7 +471,7 @@ const CreateUser = () => {
</Box>
</Wrapper>
) : (
<Redirect to='/' />
<Navigate to='/' />
);
};
+6 -6
View File
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import { useLazyQuery, useReactiveVar } from '@apollo/client';
import { Redirect } from 'react-router';
import { Navigate } from 'react-router';
import { roleVar } from '../../graphql/state';
import { Empty, Settings } from '../../assets';
import {
@@ -24,7 +24,7 @@ import { GET_ALL_FEATURES, GET_FEATURE_BY_ID } from '../../graphql/feature.api';
const Feature = () => {
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [feature, setFeature] = useState<FeatureOutput>();
@@ -82,7 +82,7 @@ const Feature = () => {
text='Settings'
iconLeft={<Settings />}
onClick={() =>
history.push(`/feature-settings/${id || feature.id}`)
navigate(`/feature-settings/${id || feature.id}`)
}
/>
</Box>
@@ -176,9 +176,9 @@ const Feature = () => {
</>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+17 -15
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory, useParams } from 'react-router';
import { Navigate, useNavigate, useParams } from 'react-router';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import React, { useEffect, useState } from 'react';
import { roleVar } from '../../graphql/state';
@@ -35,7 +35,7 @@ import {
} from '../../graphql/feature.api';
const FeatureSettings = () => {
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const role = useReactiveVar(roleVar);
@@ -45,7 +45,7 @@ const FeatureSettings = () => {
const [error, setError] = useState<string>('');
const [success, setSuccess] = useState<boolean>(false);
const [feature, setFeature] = useState<FeatureOutput>({
id,
id: id as string,
name: '',
description: '',
featureType: '',
@@ -79,7 +79,7 @@ const FeatureSettings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -89,16 +89,16 @@ const FeatureSettings = () => {
DeleteFeatureMutationVariables
>(DELETE_FEATURE, {
onCompleted() {
history.push('/feature');
navigate('/feature');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
useEffect(() => {
getFeature({ variables: { id } });
getFeature({ variables: { id: id as string } });
// eslint-disable-next-line
}, [id]);
@@ -134,7 +134,7 @@ const FeatureSettings = () => {
}) => {
updateFeature({
variables: {
id,
id: id as string,
feature: {
name,
description,
@@ -162,7 +162,7 @@ const FeatureSettings = () => {
onSubmit: ({ wireframes }) => {
updateFeature({
variables: {
id,
id: id as string,
feature: {
name: feature.name,
description: feature.description,
@@ -185,7 +185,7 @@ const FeatureSettings = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -247,7 +247,9 @@ const FeatureSettings = () => {
description='
If you delete this feature you cannot recover it.'
onClose={() => setDeleteFeatureModal(false)}
onConfirm={() => deleteFeature({ variables: { id } })}
onConfirm={() =>
deleteFeature({ variables: { id: id as string } })
}
></Modal>
)}
<form onSubmit={generalForm.handleSubmit}>
@@ -287,7 +289,7 @@ const FeatureSettings = () => {
const data = await (
await fetch(
`${process.env.REACT_APP_CLOUDINARY_URL}`,
`${import.meta.env.VITE_CLOUDINARY_URL}`,
{
method: 'POST',
body: formData,
@@ -515,7 +517,7 @@ const FeatureSettings = () => {
formData.append('upload_preset', 'xofll5kc');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
@@ -564,9 +566,9 @@ const FeatureSettings = () => {
</Wrapper>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+9 -9
View File
@@ -1,9 +1,9 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { useLazyQuery, useReactiveVar } from '@apollo/client';
import { Redirect } from 'react-router';
import { Navigate } from 'react-router';
import { roleVar } from '../../graphql/state';
import { Wrapper } from './styles';
import { Alert, Box, Button, Input, Spinner, Text } from '../../components';
@@ -34,7 +34,7 @@ type TransactionData = {
const Payments = () => {
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [project, setProject] = useState<ProjectOutput>();
const [success, setSuccess] = useState<boolean>(false);
@@ -60,7 +60,7 @@ const Payments = () => {
try {
const transactionsResult = await (
await fetch(`${process.env.REACT_APP_PAYMENT_API}/transactions`, {
await fetch(`${import.meta.env.VITE_PAYMENT_API}/transactions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -128,7 +128,7 @@ const Payments = () => {
}
const transactionsResult = await (
await fetch(`${process.env.REACT_APP_PAYMENT_API}/charge`, {
await fetch(`${import.meta.env.VITE_PAYMENT_API}/charge`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -158,7 +158,7 @@ const Payments = () => {
}
} catch (err) {
setPaymentLoading(false);
setError(err);
setError(err as string);
setSelectedChunk(undefined);
resetForm();
setTimeout(() => setError(''), 3000);
@@ -182,7 +182,7 @@ const Payments = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -494,9 +494,9 @@ const Payments = () => {
</>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'developer' ||
(role === 'productOwner' && <Redirect to='/project' />)}
(role === 'productOwner' && <Navigate to='/project' />)}
</>
);
};
+20 -25
View File
@@ -1,10 +1,10 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useReactToPrint } from 'react-to-print';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import { useEffect, useState, useRef } from 'react';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import { Redirect } from 'react-router';
import { Navigate } from 'react-router';
import { roleVar, userVar } from '../../graphql/state';
import {
Design,
@@ -80,7 +80,7 @@ type TransactionData = {
const Project = () => {
const role = useReactiveVar(roleVar);
const currentUser = useReactiveVar(userVar);
const history = useHistory();
const navigate = useNavigate();
const printRef = useRef<HTMLDivElement>(null);
const { id } = useParams<{ id: string }>();
const [project, setProject] = useState<ProjectOutput>();
@@ -91,10 +91,8 @@ const Project = () => {
const [fullBuildModal, setFullBuildModal] = useState<boolean>(false);
const [transactionsData, setTransactionsData] = useState<TransactionData>();
const [
getProjectsByClientId,
{ loading: clientProjectsLoading },
] = useLazyQuery<
const [getProjectsByClientId, { loading: clientProjectsLoading }] =
useLazyQuery<
GetAllProjectsByClientIdQuery,
GetAllProjectsByClientIdQueryVariables
>(GET_ALL_PROJECTS_BY_CLIENT_ID, {
@@ -103,7 +101,7 @@ const Project = () => {
},
onCompleted({ getAllProjectsByClientId }) {
if (getAllProjectsByClientId.length > 0)
history.push(`/project/${getAllProjectsByClientId[0].id}`);
navigate(`/project/${getAllProjectsByClientId[0].id}`);
},
fetchPolicy: 'network-only',
});
@@ -114,7 +112,7 @@ const Project = () => {
>(GET_ALL_PROJECTS, {
onCompleted({ getAllProjects }) {
if (getAllProjects.length > 0)
history.push(`/project/${getAllProjects[0].id}`);
navigate(`/project/${getAllProjects[0].id}`);
},
fetchPolicy: 'network-only',
});
@@ -146,7 +144,7 @@ const Project = () => {
setProject(changedStateProject);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -161,7 +159,7 @@ const Project = () => {
},
onError({ graphQLErrors }) {
setDesignModal(false);
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -176,7 +174,7 @@ const Project = () => {
},
onError({ graphQLErrors }) {
setMvpModal(false);
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -191,7 +189,7 @@ const Project = () => {
},
onError({ graphQLErrors }) {
setFullBuildModal(false);
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -225,7 +223,7 @@ const Project = () => {
try {
const transactionsResult = await (
await fetch(`${process.env.REACT_APP_PAYMENT_API}/transactions`, {
await fetch(`${import.meta.env.VITE_PAYMENT_API}/transactions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -336,7 +334,7 @@ const Project = () => {
addDesignForm.setFieldValue('fileSource', '');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
@@ -384,7 +382,7 @@ const Project = () => {
addMvpForm.setFieldValue('fileSource', '');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
@@ -462,7 +460,7 @@ const Project = () => {
iconLeft={<Design />}
disabled={!prototype}
onClick={() =>
history.push(`/prototype/${project.template.id}`)
navigate(`/prototype/${project.template.id}`)
}
/>
</Box>
@@ -474,9 +472,7 @@ const Project = () => {
text='Payments'
iconLeft={<Payment />}
disabled={transactionsData?.status}
onClick={() =>
history.push(`/payments/${project.id}`)
}
onClick={() => navigate(`/payments/${project.id}`)}
/>
</Box>
)}
@@ -487,9 +483,7 @@ const Project = () => {
variant='primary-action'
text='Settings'
iconLeft={<Settings />}
onClick={() =>
history.push(`/project-settings/${id}`)
}
onClick={() => navigate(`/project-settings/${id}`)}
/>
</Box>
)}
@@ -873,7 +867,8 @@ const Project = () => {
</Box>
</Box>
)}
{project.template.specification && project.template.features && (
{project.template.specification &&
project.template.features && (
<Box display='none'>
<SpecificationPrint
ref={printRef}
@@ -905,7 +900,7 @@ const Project = () => {
)}
</>
) : (
<Redirect to='/clients' />
<Navigate to='/clients' />
);
};
+50 -66
View File
@@ -1,19 +1,24 @@
import { useEffect, useState, useRef, useCallback, useMemo } from 'react';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
ControlButton,
FlowElement,
Elements,
Connection,
Edge,
ArrowHeadType,
} from 'react-flow-renderer';
import { useEffect, useState, useRef } from 'react';
import { useHistory, useParams } from 'react-router-dom';
Node,
MarkerType,
applyNodeChanges,
applyEdgeChanges,
NodeChange,
EdgeChange,
useEdgesState,
useNodesState
} from 'reactflow';
import 'reactflow/dist/style.css';
import { useNavigate, useParams } from 'react-router-dom';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import { Redirect } from 'react-router';
import { Navigate } from 'react-router';
import { roleVar } from '../../graphql/state';
import { Empty, ArrowLeft, Edit, CheckCircle } from '../../assets';
import {
@@ -29,6 +34,7 @@ import { Wrapper } from './styles';
import {
AddPrototypeMutation,
AddPrototypeMutationVariables,
FeatureOutput,
GetPrototypeByIdQuery,
GetPrototypeByIdQueryVariables,
GetTemplateByIdQuery,
@@ -47,11 +53,13 @@ import {
const Prototype = () => {
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const nodeTypes = useMemo(() => ({ featureCard: FrontendFeatureCard }), []);
const [template, setTemplate] = useState<TemplateOutput>();
const [prototype, setPrototype] = useState<Array<ProtoTypeOutput>>();
const [elements, setElements] = useState<Elements>([]);
const [nodes, setNodes, onNodesChange] = useNodesState<FeatureOutput>([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [editing, setEditing] = useState<boolean>(false);
const [error, setError] = useState<string>('');
const [success, setSuccess] = useState<boolean>(false);
@@ -86,7 +94,7 @@ const Prototype = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -107,91 +115,66 @@ const Prototype = () => {
getTemplate({ variables: { id } });
getPrototype({ variables: { id } });
}
// eslint-disable-next-line
}, [id]);
useEffect(() => {
if (template && template.features) {
const initialElements = template.features.map((feature, index) => {
if (['frontend', 'fullstack'].includes(feature.featureType)) {
return {
const initialNodes = template?.features?.map((feature, index) => ({
id: feature.id,
type: 'default',
data: {
label: <FrontendFeatureCard feature={feature} />,
},
type: 'featureCard',
data: feature,
position: { x: index * 100, y: index * 200 },
style: {
width: 'auto',
},
connectable: role === 'developer' && editing,
} as FlowElement;
}
return {} as FlowElement;
});
connectable: role === 'developer' && editing
}));
if (initialElements) setElements(initialElements);
if (initialNodes) setNodes(initialNodes);
}
if (prototype) {
const initialElements: Array<Edge> = [];
const initialEdges: Array<Edge> = [];
prototype.forEach((link) => {
link.connections.forEach((connection) => {
initialElements.push({
initialEdges.push({
id: `edge-${link.feature.id}`,
source: link.feature.id,
target: connection.to,
arrowHeadType: ArrowHeadType.ArrowClosed,
className: 'normal-edge',
markerEnd: MarkerType.Arrow,
className: 'normal-edge'
});
});
});
if (initialElements) setElements((els) => [...els, ...initialElements]);
if (initialEdges) setEdges(initialEdges);
}
// eslint-disable-next-line
}, [template, prototype, editing]);
const onElementsRemove = (elementsToRemove: Elements<any>) =>
setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Edge<any> | Connection) =>
setElements((els) =>
addEdge({ ...params, arrowHeadType: ArrowHeadType.ArrowClosed }, els)
const onConnect = useCallback(
(params: Edge | Connection) => setEdges((els) => addEdge(params, els)),
[setEdges]
);
const handleEditPrototype = () => {
if (editing) {
const prototypeInput = elements
// @ts-ignore
.filter((element) => element.source || element.target)
.map((element) => {
if (
element.hasOwnProperty('source') ||
element.hasOwnProperty('target')
) {
return {
// @ts-ignore
featureId: element.source,
const prototypeInput = edges
.map((edge) => ({
featureId: edge.source,
connections: [
{
// @ts-ignore
to: element.target,
to: edge.target,
releations: { back: false, forword: true },
},
],
};
}
return {};
});
}));
if (prototypeInput && prototypeInput.length > 0) {
if (prototype) {
updatePrototype({
variables: {
prototype: {
templateId: id,
// @ts-ignore
templateId: id as string,
prototype: prototypeInput,
},
},
@@ -200,8 +183,7 @@ const Prototype = () => {
addPrototype({
variables: {
prototype: {
templateId: id,
// @ts-ignore
templateId: id as string,
prototype: prototypeInput,
},
},
@@ -235,7 +217,7 @@ const Prototype = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -283,18 +265,20 @@ const Prototype = () => {
height='auto'
>
<ReactFlow
elements={elements}
onElementsRemove={onElementsRemove}
fitView
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
deleteKeyCode={46}
edgeTypes={{ arrowHeadType: 'arrow' }}
>
{role === 'developer' && (
<>
<MiniMap />
<Controls
showInteractive={false}
showFitView={false}
showFitView
>
<ControlButton onClick={handleEditPrototype}>
{!editing ? <Edit /> : <CheckCircle />}
@@ -364,7 +348,7 @@ const Prototype = () => {
)}
</>
) : (
<>{role === 'admin' && <Redirect to='/clients' />}</>
<>{role === 'admin' && <Navigate to='/clients' />}</>
);
};
+7 -7
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { useMutation, useQuery, useReactiveVar } from '@apollo/client';
import { useState } from 'react';
import { roleVar, tokenVar, userVar } from '../../graphql/state';
@@ -35,7 +35,7 @@ import {
} from '../../graphql/auth.api';
const Settings = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const currentUser = useReactiveVar(userVar);
const { data: countryCodes, loading: countryCodesLoading } = useQuery<
@@ -68,7 +68,7 @@ const Settings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -131,7 +131,7 @@ const Settings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -180,11 +180,11 @@ const Settings = () => {
userVar(undefined);
roleVar(undefined);
setDeleteAccountModal(false);
history.push('/signup');
navigate('/signup');
},
onError({ graphQLErrors }) {
setDeleteAccountModal(false);
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -214,7 +214,7 @@ const Settings = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
+5 -5
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useParams, useHistory } from 'react-router-dom';
import { useParams, useNavigate } from 'react-router-dom';
import { useReactiveVar } from '@apollo/client';
import { useState, useEffect } from 'react';
import { roleVar, userVar } from '../../graphql/state';
@@ -35,7 +35,7 @@ const SupportMessaging = () => {
const { project, id } = useParams<{ id: string; project: string }>();
const role = useReactiveVar(roleVar);
const currentUser = useReactiveVar(userVar);
const history = useHistory();
const navigate = useNavigate();
const [thread, setThread] = useState<ThreadObject>();
const [messages, setMessages] = useState<Array<UserMessageObject>>([]);
const [addedMessages, setAddedMessages] = useState<Array<UserMessageObject>>(
@@ -117,12 +117,12 @@ const SupportMessaging = () => {
>({
mutation: CREATE_THREAD,
variables: {
projectId: project,
projectId: project as string,
title,
threadDescription: description,
},
});
history.push(
navigate(
`/support-messaging/${project}/${createdThread.data?.createThread}`
);
},
@@ -139,7 +139,7 @@ const SupportMessaging = () => {
await clientSupport.mutate<SendMsgMutation, SendMsgMutationVariables>({
mutation: SEND_MSG,
variables: {
threadId: id,
threadId: id as string,
username: `${currentUser?.firstName} ${currentUser?.lastName}`,
msg,
},
+8 -10
View File
@@ -1,8 +1,8 @@
import { useReactToPrint } from 'react-to-print';
import { useEffect, useState, useRef } from 'react';
import { useLazyQuery, useReactiveVar } from '@apollo/client';
import { Redirect } from 'react-router';
import { useHistory, useParams } from 'react-router-dom';
import { Navigate } from 'react-router';
import { useNavigate, useParams } from 'react-router-dom';
import { roleVar } from '../../graphql/state';
import { Design, Empty, Settings, Specification } from '../../assets';
import {
@@ -38,7 +38,7 @@ import { GET_PROTOTYPE_BY_ID } from '../../graphql/prototype.api';
const Template = () => {
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const printRef = useRef<HTMLDivElement>(null);
const { id } = useParams<{ id: string }>();
const [template, setTemplate] = useState<TemplateOutput>();
@@ -61,7 +61,7 @@ const Template = () => {
>(GET_ALL_TEMPLATES, {
onCompleted({ getAllTemplates }) {
if (getAllTemplates.length > 0)
history.push(`/template/${getAllTemplates[0].id}`);
navigate(`/template/${getAllTemplates[0].id}`);
},
fetchPolicy: 'network-only',
});
@@ -150,7 +150,7 @@ const Template = () => {
prototype === undefined && role === 'productOwner'
}
onClick={() =>
history.push(`/prototype/${id || template.id}`)
navigate(`/prototype/${id || template.id}`)
}
/>
</Box>
@@ -162,9 +162,7 @@ const Template = () => {
text='Settings'
iconLeft={<Settings />}
onClick={() =>
history.push(
`/template-settings/${id || template.id}`
)
navigate(`/template-settings/${id || template.id}`)
}
/>
</Box>
@@ -269,8 +267,8 @@ const Template = () => {
</>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'client' && <Redirect to='/project' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' && <Navigate to='/project' />}
</>
);
};
+80 -66
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory, useParams } from 'react-router';
import { Navigate, useNavigate, useParams } from 'react-router';
import {
useLazyQuery,
useMutation,
@@ -47,7 +47,7 @@ import { GET_ALL_CATEGORIES } from '../../graphql/category.api';
import { GET_ALL_FEATURES } from '../../graphql/feature.api';
const TemplateSettings = () => {
const history = useHistory();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const role = useReactiveVar(roleVar);
const [template, setTemplate] = useState<TemplateOutput>({
@@ -88,9 +88,8 @@ const TemplateSettings = () => {
features: [],
});
const [availableFeatures, setAvailableFeatures] = useState<
Array<FeatureOutput>
>();
const [availableFeatures, setAvailableFeatures] =
useState<Array<FeatureOutput>>();
const [selectedSection, setSelectedSection] = useState<
'general' | 'specification' | 'features'
@@ -98,9 +97,8 @@ const TemplateSettings = () => {
const [error, setError] = useState<string>('');
const [success, setSuccess] = useState<boolean>(false);
const [deleteTemplateModal, setDeleteTemplateModal] = useState<boolean>(
false
);
const [deleteTemplateModal, setDeleteTemplateModal] =
useState<boolean>(false);
const { data: categories, loading: categoriesLoading } = useQuery<
GetAllCategoriesQuery,
@@ -139,7 +137,7 @@ const TemplateSettings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -149,16 +147,16 @@ const TemplateSettings = () => {
DeleteTemplateMutationVariables
>(DELETE_TEMPLATE, {
onCompleted() {
history.push('/template');
navigate('/template');
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
useEffect(() => {
getTemplate({ variables: { id } });
getTemplate({ variables: { id: id as string } });
getFeatures();
// eslint-disable-next-line
@@ -189,7 +187,7 @@ const TemplateSettings = () => {
});
updateTemplate({
variables: {
id,
id: id as string,
template: {
name,
description,
@@ -203,35 +201,42 @@ const TemplateSettings = () => {
specification: {
introduction: {
purpose: template.specification?.introduction.purpose!,
documentConventions: template.specification?.introduction
.documentConventions!,
intendedAudience: template.specification?.introduction
.intendedAudience!,
documentConventions:
template.specification?.introduction.documentConventions!,
intendedAudience:
template.specification?.introduction.intendedAudience!,
projectScope: template.specification?.introduction.projectScope!,
},
overallDescription: {
perspective: template.specification?.overallDescription
.perspective!,
userCharacteristics: template.specification?.overallDescription
.userCharacteristics!,
operatingEnvironment: template.specification?.overallDescription
perspective:
template.specification?.overallDescription.perspective!,
userCharacteristics:
template.specification?.overallDescription.userCharacteristics!,
operatingEnvironment:
template.specification?.overallDescription
.operatingEnvironment!,
designImplementationConstraints: template.specification
?.overallDescription.designImplementationConstraints!,
userDocumentation: template.specification?.overallDescription
.userDocumentation!,
assemptionsDependencies: template.specification
?.overallDescription.assemptionsDependencies!,
designImplementationConstraints:
template.specification?.overallDescription
.designImplementationConstraints!,
userDocumentation:
template.specification?.overallDescription.userDocumentation!,
assemptionsDependencies:
template.specification?.overallDescription
.assemptionsDependencies!,
},
nonFunctionalRequirements: {
performanceRequirements: template.specification
?.nonFunctionalRequirements.performanceRequirements!,
safetyRequirements: template.specification
?.nonFunctionalRequirements.safetyRequirements!,
securityRequirements: template.specification
?.nonFunctionalRequirements.securityRequirements!,
softwareQualityAttributes: template.specification
?.nonFunctionalRequirements.softwareQualityAttributes!,
performanceRequirements:
template.specification?.nonFunctionalRequirements
.performanceRequirements!,
safetyRequirements:
template.specification?.nonFunctionalRequirements
.safetyRequirements!,
securityRequirements:
template.specification?.nonFunctionalRequirements
.securityRequirements!,
softwareQualityAttributes:
template.specification?.nonFunctionalRequirements
.softwareQualityAttributes!,
},
otherRequirements: template.specification?.otherRequirements!,
glossary: template.specification?.glossary!,
@@ -375,7 +380,7 @@ const TemplateSettings = () => {
});
updateTemplate({
variables: {
id,
id: id as string,
template: {
name: template.name,
description: template.description,
@@ -425,7 +430,7 @@ const TemplateSettings = () => {
onSubmit: ({ features }) => {
updateTemplate({
variables: {
id,
id: id as string,
template: {
name: template.name,
description: template.description,
@@ -439,35 +444,42 @@ const TemplateSettings = () => {
specification: {
introduction: {
purpose: template.specification?.introduction.purpose!,
documentConventions: template.specification?.introduction
.documentConventions!,
intendedAudience: template.specification?.introduction
.intendedAudience!,
documentConventions:
template.specification?.introduction.documentConventions!,
intendedAudience:
template.specification?.introduction.intendedAudience!,
projectScope: template.specification?.introduction.projectScope!,
},
overallDescription: {
perspective: template.specification?.overallDescription
.perspective!,
userCharacteristics: template.specification?.overallDescription
.userCharacteristics!,
operatingEnvironment: template.specification?.overallDescription
perspective:
template.specification?.overallDescription.perspective!,
userCharacteristics:
template.specification?.overallDescription.userCharacteristics!,
operatingEnvironment:
template.specification?.overallDescription
.operatingEnvironment!,
designImplementationConstraints: template.specification
?.overallDescription.designImplementationConstraints!,
userDocumentation: template.specification?.overallDescription
.userDocumentation!,
assemptionsDependencies: template.specification
?.overallDescription.assemptionsDependencies!,
designImplementationConstraints:
template.specification?.overallDescription
.designImplementationConstraints!,
userDocumentation:
template.specification?.overallDescription.userDocumentation!,
assemptionsDependencies:
template.specification?.overallDescription
.assemptionsDependencies!,
},
nonFunctionalRequirements: {
performanceRequirements: template.specification
?.nonFunctionalRequirements.performanceRequirements!,
safetyRequirements: template.specification
?.nonFunctionalRequirements.safetyRequirements!,
securityRequirements: template.specification
?.nonFunctionalRequirements.securityRequirements!,
softwareQualityAttributes: template.specification
?.nonFunctionalRequirements.softwareQualityAttributes!,
performanceRequirements:
template.specification?.nonFunctionalRequirements
.performanceRequirements!,
safetyRequirements:
template.specification?.nonFunctionalRequirements
.safetyRequirements!,
securityRequirements:
template.specification?.nonFunctionalRequirements
.securityRequirements!,
softwareQualityAttributes:
template.specification?.nonFunctionalRequirements
.softwareQualityAttributes!,
},
otherRequirements: template.specification?.otherRequirements!,
glossary: template.specification?.glossary!,
@@ -487,7 +499,7 @@ const TemplateSettings = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -541,7 +553,9 @@ const TemplateSettings = () => {
description='
If you delete this template you cannot recover it.'
onClose={() => setDeleteTemplateModal(false)}
onConfirm={() => deleteTemplate({ variables: { id } })}
onConfirm={() =>
deleteTemplate({ variables: { id: id as string } })
}
></Modal>
)}
<Box
@@ -599,7 +613,7 @@ const TemplateSettings = () => {
const data = await (
await fetch(
`${process.env.REACT_APP_CLOUDINARY_URL}`,
`${import.meta.env.VITE_CLOUDINARY_URL}`,
{
method: 'POST',
body: formData,
@@ -1064,9 +1078,9 @@ const TemplateSettings = () => {
</Wrapper>
) : (
<>
{role === 'admin' && <Redirect to='/clients' />}
{role === 'admin' && <Navigate to='/clients' />}
{role === 'client' ||
(role === 'developer' && <Redirect to='/project' />)}
(role === 'developer' && <Navigate to='/project' />)}
</>
);
};
+7 -7
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useHistory, useParams } from 'react-router';
import { useNavigate, useParams } from 'react-router';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import { useState, useEffect } from 'react';
import { roleVar } from '../../graphql/state';
@@ -18,7 +18,7 @@ import { ArrowLeft } from '../../assets';
import { theme } from '../../themes';
const UpdateProject = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const [error, setError] = useState<string>('');
const [project, setProject] = useState<ProjectOutput>();
@@ -39,10 +39,10 @@ const UpdateProject = () => {
UpdateProjectMutationVariables
>(UPDATE_PROJECT, {
onCompleted() {
history.push(`/project/${id}`);
navigate(`/project/${id}`);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0].extensions?.info);
setError(graphQLErrors[0].extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -69,7 +69,7 @@ const UpdateProject = () => {
onSubmit: ({ name, imageName, imageSource }) => {
updateProject({
variables: {
id,
id: id as string,
name,
image: { name: imageName, src: imageSource },
},
@@ -92,7 +92,7 @@ const UpdateProject = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -157,7 +157,7 @@ const UpdateProject = () => {
basicInfoForm.setFieldValue('imageSource', '');
const data = await (
await fetch(`${process.env.REACT_APP_CLOUDINARY_URL}`, {
await fetch(`${import.meta.env.VITE_CLOUDINARY_URL}`, {
method: 'POST',
body: formData,
})
+7 -7
View File
@@ -1,6 +1,6 @@
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Redirect, useHistory, useParams } from 'react-router';
import { Navigate, useNavigate, useParams } from 'react-router';
import { useMutation, useQuery, useReactiveVar } from '@apollo/client';
import { useState } from 'react';
import { roleVar } from '../../graphql/state';
@@ -35,7 +35,7 @@ import {
} from '../../graphql/auth.api';
const UserSettings = () => {
const history = useHistory();
const navigate = useNavigate();
const role = useReactiveVar(roleVar);
const [userToEdit, setUserToEdit] = useState<UserOutput>();
const { id } = useParams<{ id: string }>();
@@ -48,7 +48,7 @@ const UserSettings = () => {
GetUserByIdQueryVariables
>(GET_USER_BY_ID, {
variables: {
id,
id: id as string,
},
onCompleted({ getUserById }) {
setUserToEdit(getUserById);
@@ -79,7 +79,7 @@ const UserSettings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -143,7 +143,7 @@ const UserSettings = () => {
setTimeout(() => setSuccess(false), 3000);
},
onError({ graphQLErrors }) {
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -189,7 +189,7 @@ const UserSettings = () => {
text='Back'
color={role || 'client'}
size='small'
onClick={() => history.goBack()}
onClick={() => navigate(-1)}
iconLeft={<ArrowLeft />}
/>
<Text variant='headline' weight='bold'>
@@ -481,7 +481,7 @@ const UserSettings = () => {
</Box>
</Wrapper>
) : (
<Redirect to='/' />
<Navigate to='/' />
);
};
+7 -9
View File
@@ -2,7 +2,7 @@ import * as Yup from 'yup';
import { useFormik } from 'formik';
import { useMutation, useLazyQuery, useReactiveVar } from '@apollo/client';
import { useEffect, useState } from 'react';
import { Redirect, useHistory, useLocation } from 'react-router';
import { Navigate, useNavigate, useLocation } from 'react-router';
import { roleVar } from '../../graphql/state';
import { Add, Delete, Edit, Empty } from '../../assets';
import {
@@ -27,7 +27,7 @@ import { DELETE_USER } from '../../graphql/auth.api';
const Users = () => {
const role = useReactiveVar(roleVar);
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
const [users, setUsers] = useState<Array<UserOutput>>();
const [userToDelete, setUserToDelete] = useState<UserOutput>();
@@ -67,7 +67,7 @@ const Users = () => {
},
onError({ graphQLErrors }) {
setDeleteAccountModal(false);
setError(graphQLErrors[0]?.extensions?.info);
setError(graphQLErrors[0]?.extensions?.info as string);
setTimeout(() => setError(''), 3000);
},
});
@@ -154,7 +154,7 @@ const Users = () => {
}`}
iconLeft={<Add />}
onClick={() =>
history.push(
navigate(
`/create-user/${
location.pathname === '/clients'
? 'Client'
@@ -220,9 +220,7 @@ const Users = () => {
justifySelf='flex-end'
>
<Box
onClick={() =>
history.push(`/user-settings/${user.id}`)
}
onClick={() => navigate(`/user-settings/${user.id}`)}
marginRight='15px'
cursor='pointer'
>
@@ -273,7 +271,7 @@ const Users = () => {
}`}
iconLeft={<Add />}
onClick={() =>
history.push(
navigate(
`/create-user/${
location.pathname === '/clients'
? 'Client'
@@ -304,7 +302,7 @@ const Users = () => {
)}
</>
) : (
<Redirect to='/clients' />
<Navigate to='/clients' />
);
};
+2 -1
View File
@@ -1,12 +1,13 @@
{
"compilerOptions": {
"target": "es5",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"types": ["node", "vite/client"],
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
+7
View File
@@ -0,0 +1,7 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";
export default defineConfig({
plugins: [svgr(), react()],
})
+2948 -11061
View File
File diff suppressed because it is too large Load Diff