fix form issues

This commit is contained in:
Simon Larsen 2022-06-29 21:51:49 +01:00
parent 07eacc0a19
commit 173c03730a
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
31 changed files with 302 additions and 160 deletions

View File

@ -4,14 +4,20 @@ import LoginPage from './Pages/Login';
import SsoLoginPage from './Pages/SsoLogin';
import ForgotPasswordPage from './Pages/ForgotPassword';
import RegisterPage from './Pages/Register';
import { DASHBOARD_URL } from 'CommonUI/src/Config';
import 'CommonUI/src/Styles/theme.scss';
import Navigation from 'CommonUI/src/Utils/Navigation';
import VerifyEmail from './Pages/VerifyEmail';
import User from 'CommonUI/src/Utils/User';
function App(): ReactElement {
Navigation.setNavigateHook(useNavigate());
Navigation.setLocation(useLocation());
if (User.isLoggedIn()) {
Navigation.navigate(DASHBOARD_URL);
}
return (
<div className="App">
<Routes>

View File

@ -1,28 +1,24 @@
import React, { FunctionComponent, useState } from 'react';
import BasicModelForm from 'CommonUI/src/Components/Forms/BasicModelForm';
import React, { FunctionComponent } from 'react';
import ModelForm, { FormType } from 'CommonUI/src/Components/Forms/ModelForm';
import User from 'Common/Models/User';
import FormValues from 'CommonUI/src/Components/Forms/Types/FormValues';
import IdentityAPI from 'CommonUI/src/Utils/API/IdentityAPI';
import Link from 'CommonUI/src/Components/Link/Link';
import Route from 'Common/Types/API/Route';
import { JSONObject } from 'Common/Types/JSON';
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimePNG/7.png';
import { DASHBOARD_URL } from 'CommonUI/src/Config';
import { JSONObject } from 'Common/Types/JSON';
import UserUtil from "CommonUI/src/Utils/User";
import Navigation from 'CommonUI/src/Utils/Navigation';
import Email from 'Common/Types/Email';
import ObjectID from 'Common/Types/ObjectID';
import Name from 'Common/Types/Name';
import URL from 'Common/Types/API/URL';
import { SIGNUP_API_URL } from "../Utils/ApiPaths";
const RegisterPage: FunctionComponent = () => {
const [isLaoding, setIsLoading] = useState<boolean>(false);
const user: User = new User();
const submitForm: Function = async (values: FormValues<User>) => {
setIsLoading(true);
await IdentityAPI.post<JSONObject>(new Route('/signup'), {
user: values as JSONObject,
});
setIsLoading(false);
};
const apiUrl: URL = SIGNUP_API_URL;
return (
<div className="auth-page">
@ -55,12 +51,21 @@ const RegisterPage: FunctionComponent = () => {
</p>
</div>
<BasicModelForm<User>
<ModelForm<User>
model={user}
isLoading={isLaoding}
id="register-form"
showAsColumns={2}
maxPrimaryButtonWidth={true}
initialValues= {
{
email: '',
name: '',
companyName: '',
companyPhoneNumber: '',
password: '',
confirmPassword: ''
}
}
fields={[
{
field: {
@ -89,7 +94,7 @@ const RegisterPage: FunctionComponent = () => {
},
fieldType:
FormFieldSchemaType.Text,
placeholder: 'Company Name',
placeholder: 'Acme, Inc.',
required: true,
title: 'Company Name',
},
@ -101,7 +106,7 @@ const RegisterPage: FunctionComponent = () => {
fieldType:
FormFieldSchemaType.Text,
required: true,
placeholder: 'Phone Number',
placeholder: '+1-123-456-7890',
title: 'Phone Number',
},
{
@ -136,8 +141,22 @@ const RegisterPage: FunctionComponent = () => {
required: true,
},
]}
onSubmit={submitForm}
apiUrl={apiUrl}
formType={FormType.Create}
submitButtonText={'Sign Up'}
onSuccess={(value: JSONObject) => {
const user: User = User.fromJSON(value["user"] as JSONObject, User) as User;
const token: string = value["token"] as string;
UserUtil.setAccessToken(token);
UserUtil.setEmail(user.email as Email);
UserUtil.setUserId(user.id as ObjectID);
UserUtil.setName(user.name as Name);
// go to dashboard, user should be logged in.
Navigation.navigate(DASHBOARD_URL);
}}
/>
<div className="mt-5 text-center">

View File

@ -0,0 +1,5 @@
import Route from 'Common/Types/API/Route';
import URL from 'Common/Types/API/URL';
import { IDENTITY_URL } from 'CommonUI/src/Config';
export const SIGNUP_API_URL: URL = IDENTITY_URL.addRoute(new Route("/signup"));

View File

@ -63,5 +63,5 @@ module.exports = {
writeToDisk: true,
},
},
devtool: 'inline-source-map',
devtool: 'eval-source-map',
}

View File

@ -27,6 +27,7 @@ import HashedString from '../Types/HashedString';
import Email from '../Types/Email';
import Phone from '../Types/Phone';
import PositiveNumber from '../Types/PositiveNumber';
import Route from '../Types/API/Route';
export type DbTypes =
| string
@ -100,6 +101,7 @@ export default class BaseModel extends BaseEntity {
public slugifyColumn!: string | null;
public saveSlugToColumn!: string | null;
public crudApiPath!: Route | null;
// If this resource is by projectId, which column does projectId belong to?
public projectIdColumn!: string | null;
@ -621,6 +623,10 @@ export default class BaseModel extends BaseEntity {
return this.slugifyColumn;
}
public getCrudApiPath(): Route | null {
return this.crudApiPath;
}
public getSaveSlugToColumn(): string | null {
return this.saveSlugToColumn;
}

View File

@ -6,7 +6,10 @@ import User from './User';
import ColumnLength from '../Types/Database/ColumnLength';
import Email from '../Types/Email';
import TableColumn from '../Types/Database/TableColumn';
import CrudApiEndpoint from '../Types/Database/CrudApiEndpoint';
import Route from '../Types/API/Route';
@CrudApiEndpoint(new Route("/email-verification-token"))
@Entity({
name: 'EmailVerificationToken',
})

View File

@ -9,7 +9,10 @@ import SlugifyColumn from '../Types/Database/SlugifyColumn';
import URL from '../Types/API/URL';
import User from './User';
import TableColumn from '../Types/Database/TableColumn';
import CrudApiEndpoint from '../Types/Database/CrudApiEndpoint';
import Route from '../Types/API/Route';
@CrudApiEndpoint(new Route("/probe"))
@SlugifyColumn('name', 'slug')
@Entity({
name: 'Probe',

View File

@ -6,7 +6,10 @@ import PositiveNumber from '../Types/PositiveNumber';
import ObjectID from '../Types/ObjectID';
import ColumnLength from '../Types/Database/ColumnLength';
import TableColumn from '../Types/Database/TableColumn';
import CrudApiEndpoint from '../Types/Database/CrudApiEndpoint';
import Route from '../Types/API/Route';
@CrudApiEndpoint(new Route("/project"))
@Entity({
name: 'Project',
})

View File

@ -14,7 +14,10 @@ import HashedString from '../Types/HashedString';
import PublicRecordPermissions from '../Types/Database/AccessControls/Public/PublicRecordPermissions';
import TableColumn from '../Types/Database/TableColumn';
import PublicColumnPermissions from '../Types/Database/AccessControls/Public/PublicColumnPermissions';
import CrudApiEndpoint from '../Types/Database/CrudApiEndpoint';
import Route from '../Types/API/Route';
@CrudApiEndpoint(new Route("/user"))
@PublicRecordPermissions({
create: true,
readAsList: false,

View File

@ -31,14 +31,30 @@ export default class HTTPResponse<
public constructor(statusCode: number, data: JSONObjectOrArray) {
this.statusCode = statusCode;
this.jsonData = data;
this.data = data as T;
}
let obj!: T;
public isSuccess(): boolean {
return this.statusCode === 200;
}
if (obj instanceof BaseModel) {
// this.data = BaseModel.fromJSON(data) as T;
this.data = data as T;
} else {
this.data = data as T;
}
public isFailure(): boolean {
return this.statusCode !== 200;
}
public isNotAuthorized(): boolean {
return this.statusCode === 401;
}
public isTooManyRequests(): boolean {
return this.statusCode === 429;
}
public isPaymentDeclined(): boolean {
return this.statusCode === 402;
}
public isServerError(): boolean {
return this.statusCode === 500;
}
}

View File

@ -24,8 +24,8 @@ export default class Route {
if (this.route.endsWith('/') && routeToBeAdded.trim().startsWith('/')) {
routeToBeAdded = routeToBeAdded.trim().substring(1); // remove leading "/" from route
}
const newRoute: Route = new Route(this.route + routeToBeAdded);
return newRoute;
this.route = new Route(this.route + routeToBeAdded).route;
return this;
}
public toString(): string {

View File

@ -103,6 +103,16 @@ export default class URL extends DatabaseProperty {
return new URL(protocol, hostname, route);
}
public addRoute(route: Route | string): URL {
if (typeof route === "string") {
this.route.addRoute(new Route(route));
} else {
this.route.addRoute(route);
}
return this;
}
protected static override toDatabase(
value: URL | FindOperator<URL>
): string | null {
@ -113,6 +123,8 @@ export default class URL extends DatabaseProperty {
return null;
}
protected static override fromDatabase(_value: string): URL | null {
if (_value) {
return URL.fromString(_value);

View File

@ -0,0 +1,7 @@
import Route from "../API/Route";
export default (apiPath: Route) => {
return (ctr: Function) => {
ctr.prototype.CrudApiPath = apiPath;
};
};

View File

@ -192,7 +192,7 @@ export default class API {
return await this.fetch(HTTPMethod.POST, url, data, headers);
}
private static async fetch<
public static async fetch<
T extends JSONObject | JSONArray | BaseModel | Array<BaseModel>
>(
method: HTTPMethod,

View File

@ -79,17 +79,21 @@ app.use(
res: ExpressResponse,
next: NextFunction
) => {
logger.error("Code");
logger.error(err);
if (res.headersSent) {
return next(err);
}
logger.error("Code");
logger.error((err as Exception).code);
if (err instanceof Exception) {
logger.error("Exception Error")
res.status((err as Exception).code);
res.send({ error: (err as Exception).message });
} else {
res.status(500);
res.status(400);
res.send({ error: err });
}
}

View File

@ -4,7 +4,8 @@ import ShortcutKey from '../ShortcutKey/ShortcutKey';
import ButtonType from './ButtonTypes';
import CSS from 'csstype';
import Icon, { IconProp, SizeProp, ThickProp } from '../Icon/Icon';
import Loader, { LoaderType } from '../Loader/Loader';
import { White } from '../../Utils/BrandColors';
export enum ButtonStyleType {
PRIMARY,
SECONDRY,
@ -164,7 +165,7 @@ const Button: FunctionComponent<ComponentProps> = ({
</span>
</div>
)}
{isLoading && <div>Implement Loader here</div>}
{isLoading && <div><Loader loaderType={LoaderType.Beats} color={White} size={10} /></div>}
</button>
);
};

View File

@ -10,6 +10,7 @@ import { JSONObject } from 'Common/Types/JSON';
import FormFieldSchemaType from './Types/FormFieldSchemaType';
import Email from 'Common/Types/Email';
import Link from '../Link/Link';
import Alert, { AlertType } from '../Alerts/Alert';
export const DefaultValidateFunction: Function = (
_values: FormValues<JSONObject>
@ -32,6 +33,7 @@ export interface ComponentProps<T extends Object> {
onCancel?: (() => void) | null;
cancelButtonText?: string | null;
maxPrimaryButtonWidth?: boolean;
error: string | null
}
function getFieldType(fieldType: FormFieldSchemaType): string {
@ -50,9 +52,12 @@ function getFieldType(fieldType: FormFieldSchemaType): string {
const BasicForm: Function = <T extends Object>(
props: ComponentProps<T>
): ReactElement => {
const getFormField: Function = (
field: DataField<T>,
index: number
index: number,
isDisabled: boolean
): ReactElement => {
const fieldType: string = field.fieldType
? getFieldType(field.fieldType)
@ -65,10 +70,14 @@ const BasicForm: Function = <T extends Object>(
if (props.showAsColumns && props.showAsColumns > 2) {
throw new BadDataException(
'showAsCOlumns should be <= 2. It is currently ' +
props.showAsColumns
props.showAsColumns
);
}
const fieldName: string = field.overideFieldKey
? field.overideFieldKey
: (Object.keys(field.field)[0] as string);
return (
<div className="mb-3" key={index}>
<label className="form-Label form-label justify-space-between width-max">
@ -94,10 +103,9 @@ const BasicForm: Function = <T extends Object>(
type={fieldType}
tabIndex={index + 1}
name={
field.overideFieldKey
? field.overideFieldKey
: (Object.keys(field.field)[0] as string)
fieldName
}
disabled={isDisabled}
/>
<ErrorMessage
className="mt-1 text-danger"
@ -119,17 +127,15 @@ const BasicForm: Function = <T extends Object>(
if (field.validation) {
if (field.validation.minLength) {
if (content.trim().length < field.validation?.minLength) {
return `${field.title || name} cannot be less than ${
field.validation.minLength
} characters.`;
return `${field.title || name} cannot be less than ${field.validation.minLength
} characters.`;
}
}
if (field.validation.maxLength) {
if (content.trim().length > field.validation?.maxLength) {
return `${field.title || name} cannot be more than ${
field.validation.maxLength
} characters.`;
return `${field.title || name} cannot be more than ${field.validation.maxLength
} characters.`;
}
}
}
@ -156,7 +162,7 @@ const BasicForm: Function = <T extends Object>(
field.validation?.toMatchField &&
entity[field.validation?.toMatchField] &&
(entity[field.validation?.toMatchField] as string).trim() !==
content.trim()
content.trim()
) {
return `${field.title} should match ${field.validation?.toMatchField}`;
}
@ -179,69 +185,70 @@ const BasicForm: Function = <T extends Object>(
values: FormValues<T>
) => void | object | Promise<FormikErrors<FormValues<T>>>) &
Function = (values: FormValues<T>): FormikErrors<FormValues<T>> => {
const errors: JSONObject = {};
const entries: JSONObject = { ...values } as JSONObject;
for (const field of props.fields) {
const name: string = field.overideFieldKey
? field.overideFieldKey
: (Object.keys(field.field)[0] as string);
if (name in values) {
const content: string | undefined = entries[name]?.toString();
const errors: JSONObject = {};
const entries: JSONObject = { ...values } as JSONObject;
if (content) {
// Check Required fields.
const resultRequired: string | null = validateRequired(
content,
field
);
if (resultRequired) {
errors[name] = resultRequired;
}
// Check for valid email data.
const resultValidateData: string | null = validateData(
content,
field
);
if (resultValidateData) {
errors[name] = resultValidateData;
}
const resultMatch: string | null = validateMatchField(
content,
field,
entries
);
if (resultMatch) {
errors[name] = resultMatch;
}
// check for length of content
const result: string | null = validateLength(
content,
field
);
if (result) {
errors[name] = result;
for (const field of props.fields) {
const name: string = field.overideFieldKey
? field.overideFieldKey
: (Object.keys(field.field)[0] as string);
if (name in values) {
const content: string | undefined = entries[name]?.toString();
if (content) {
// Check Required fields.
const resultRequired: string | null = validateRequired(
content,
field
);
if (resultRequired) {
errors[name] = resultRequired;
}
// Check for valid email data.
const resultValidateData: string | null = validateData(
content,
field
);
if (resultValidateData) {
errors[name] = resultValidateData;
}
const resultMatch: string | null = validateMatchField(
content,
field,
entries
);
if (resultMatch) {
errors[name] = resultMatch;
}
// check for length of content
const result: string | null = validateLength(
content,
field
);
if (result) {
errors[name] = result;
}
}
} else if (field.required) {
errors[name] = `${field.title || name} is required.`;
}
} else if (field.required) {
errors[name] = `${field.title || name} is required.`;
}
}
let customValidateResult: JSONObject = {};
let customValidateResult: JSONObject = {};
if (props.onValidate) {
customValidateResult = props.onValidate(values);
}
if (props.onValidate) {
customValidateResult = props.onValidate(values);
}
return { ...errors, ...customValidateResult } as FormikErrors<
FormValues<T>
>;
};
return { ...errors, ...customValidateResult } as FormikErrors<
FormValues<T>
>;
};
return (
<div className="row">
@ -259,6 +266,7 @@ const BasicForm: Function = <T extends Object>(
setSubmitting(false);
}}
>
<Form autoComplete="off">
<h1>{props.title}</h1>
@ -266,40 +274,38 @@ const BasicForm: Function = <T extends Object>(
<p className="description">{props.description}</p>
)}
{props.error && <Alert title={props.error} type={AlertType.DANGER} />}
<div className={`col-lg-12 flex`}>
<div
className={`col-lg-${
12 / (props.showAsColumns || 1)
} ${
(props.showAsColumns || 1) > 1
className={`col-lg-${12 / (props.showAsColumns || 1)
} ${(props.showAsColumns || 1) > 1
? 'pr-10'
: ''
}`}
}`}
>
{props.fields &&
props.fields.map(
(field: DataField<T>, i: number) => {
if (
i %
(props.showAsColumns ||
1) ===
(props.showAsColumns ||
1) ===
0
) {
return getFormField(field, i);
return getFormField(field, i, props.isLoading);
}
return <></>;
return <div key={i}></div>;
}
)}
</div>
{(props.showAsColumns || 1) > 1 && (
<div
className={`col-lg-${
12 / (props.showAsColumns || 1)
} ${
(props.showAsColumns || 1) > 1
className={`col-lg-${12 / (props.showAsColumns || 1)
} ${(props.showAsColumns || 1) > 1
? 'pl-10'
: ''
}`}
}`}
>
{props.fields &&
props.fields.map(
@ -309,16 +315,17 @@ const BasicForm: Function = <T extends Object>(
) => {
if (
i %
(props.showAsColumns ||
1) !==
(props.showAsColumns ||
1) !==
0
) {
return getFormField(
field,
i
i,
props.isLoading
);
}
return <></>;
return <div key={i}></div>;
}
)}
</div>
@ -342,6 +349,7 @@ const BasicForm: Function = <T extends Object>(
title={props.submitButtonText || 'Submit'}
type={ButtonTypes.Submit}
id={`${props.id}-submit-button`}
disabled={props.isLoading || false}
isLoading={props.isLoading || false}
buttonStyle={ButtonStyleType.PRIMARY}
style={{

View File

@ -22,6 +22,7 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
onCancel?: () => void;
cancelButtonText?: string;
maxPrimaryButtonWidth?: boolean;
error: string | null
}
const BasicModelForm: Function = <TBaseModel extends BaseModel>(
@ -75,6 +76,7 @@ const BasicModelForm: Function = <TBaseModel extends BaseModel>(
onCancel={props.onCancel}
cancelButtonText={props.cancelButtonText}
maxPrimaryButtonWidth={props.maxPrimaryButtonWidth || false}
error={props.error}
></BasicForm>
);
};

View File

@ -4,10 +4,19 @@ import BaseModel from 'Common/Models/BaseModel';
import FormValues from './Types/FormValues';
import Fields from './Types/Fields';
import BasicModelForm from './BasicModelForm';
import { JSONArray, JSONObject, JSONObjectOrArray } from 'Common/Types/JSON';
import URL from 'Common/Types/API/URL';
import HTTPMethod from 'Common/Types/API/HTTPMethod';
import API from '../../Utils/API/API';
import HTTPResponse from 'Common/Types/API/HTTPResponse';
import Route from 'Common/Types/API/Route';
import BadDataException from 'Common/Types/Exception/BadDataException';
import { DASHBOARD_API_URL } from '../../Config';
export enum FormType {
Create,
Update,
Update
}
export interface ComponentProps<TBaseModel extends BaseModel> {
@ -23,30 +32,51 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
showAsColumns?: number;
footer: ReactElement;
onCancel?: () => void;
onSuccess?: (data: TBaseModel) => void;
onSuccess?: (data: TBaseModel | JSONObjectOrArray | Array<TBaseModel>) => void;
cancelButtonText?: string;
maxPrimaryButtonWidth?: boolean;
apiUrl?: URL,
formType: FormType
}
const CreateModelForm: Function = <TBaseModel extends BaseModel>(
props: ComponentProps<TBaseModel>
): ReactElement => {
const [isLoading] = useState<boolean>(false);
// const [data, setData] = useState<TBaseModel>(props.model);
const [isLoading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string>('');
// useEffect(() => {
const onSubmit = async (values: any) => {
// Ping an API here.
setLoading(true);
let apiUrl = props.apiUrl;
// let httpMethod: HTTPMethod = HTTPMethod.POST;
if (!apiUrl) {
const apiPath: Route | null = props.model.getCrudApiPath();
if (!apiPath) {
throw new BadDataException("This model does not support CRUD operations.");
}
/*
* if (props.formType === FormType.Update) {
* httpMethod = HTTPMethod.PUT;
* setIsLoading(true);
* // Need to fetch data;
*/
apiUrl = DASHBOARD_API_URL.addRoute(apiPath);
}
// }
const result: HTTPResponse<JSONObject | JSONArray | TBaseModel | Array<TBaseModel>> =
await API.fetch<
JSONObject |
JSONArray |
TBaseModel |
Array<TBaseModel
>>(props.formType === FormType.Create ? HTTPMethod.POST : HTTPMethod.PUT, apiUrl, values);
// }, []);
setLoading(false);
if (result.isSuccess()) {
if (props.onSuccess) {
props.onSuccess(result.data);
}
} else {
setError((result.data as JSONObject)["error"] as string)
}
};
return (
<BasicModelForm<TBaseModel>
@ -60,14 +90,11 @@ const CreateModelForm: Function = <TBaseModel extends BaseModel>(
isLoading={isLoading}
submitButtonText={props.submitButtonText}
cancelButtonText={props.cancelButtonText}
onSubmit={async (_values: any) => {
// Ping POST an API here.
if (props.onSuccess) {
props.onSuccess(props.model);
}
}}
onSubmit={onSubmit}
onValidate={props.onValidate}
onCancel={props.onCancel}
maxPrimaryButtonWidth={props.maxPrimaryButtonWidth}
error={error}
></BasicModelForm>
);
};

View File

@ -1,9 +1,11 @@
import BarLoader from 'react-spinners/BarLoader';
import BeatLoader from 'react-spinners/BeatLoader';
import React, { FunctionComponent } from 'react';
import Color from 'Common/Types/Color';
export enum LoaderType {
Bar,
Beats
}
export interface ComponentProps {
@ -17,10 +19,15 @@ const Loader: FunctionComponent<ComponentProps> = ({
color = new Color('#000000'),
loaderType = LoaderType.Bar,
}: ComponentProps) => {
if (loaderType === LoaderType.Bar) {
return <BarLoader height={4} width={size} color={color.toString()} />;
}
if (loaderType === LoaderType.Beats) {
return <BeatLoader size={size} color={color.toString()} />;
}
return <></>;
};

View File

@ -72,8 +72,8 @@ export const HOME_HOSTNAME: Hostname = Hostname.fromString(
export const DASHBOARD_API_URL: URL = new URL(
HTTP_PROTOCOL,
INTEGRATION_HOSTNAME,
INTEGRATION_ROUTE
DASHBOARD_API_HOSTNAME,
DASHBOARD_API_ROUTE
);
export const IDENTITY_URL: URL = new URL(

View File

@ -1,5 +1,4 @@
import User from '../User';
import history from '../History';
import Headers from 'Common/Types/API/Headers';
import API from 'Common/Utils/API';
import APIException from 'Common/Types/Exception/ApiException';
@ -8,12 +7,18 @@ import Cookies from 'universal-cookie';
import Protocol from 'Common/Types/API/Protocol';
import Hostname from 'Common/Types/API/Hostname';
import Route from 'Common/Types/API/Route';
import URL from 'Common/Types/API/URL';
import Navigation from '../Navigation';
class BaseAPI extends API {
public constructor(protocol: Protocol, hostname: Hostname, route?: Route) {
super(protocol, hostname, route);
}
public static fromURL(url: URL) {
return new BaseAPI(url.protocol, url.hostname, url.route);
}
protected static override getHeaders(): Headers {
let defaultHeaders: Headers = this.getDefaultHeaders();
@ -38,7 +43,7 @@ class BaseAPI extends API {
cookies.remove('admin-data', { path: '/' });
cookies.remove('data', { path: '/' });
User.clear();
history.push('/login');
Navigation.navigate(new Route("/accounts/login"));
}
return error;

View File

@ -3,7 +3,7 @@ import {
HTTP_PROTOCOL,
DASHBOARD_API_ROUTE,
} from '../../Config';
import BaseAPI from './BaseAPI';
import BaseAPI from './API';
class BackendAPI extends BaseAPI {
public constructor() {

View File

@ -1,5 +1,5 @@
import { IDENTITY_HOSTNAME, HTTP_PROTOCOL, IDENTITY_ROUTE } from '../../Config';
import BaseAPI from './BaseAPI';
import BaseAPI from './API';
class IdentityAPI extends BaseAPI {
public constructor() {

View File

@ -1,5 +1,5 @@
import { INTEGRATION_HOSTNAME, HTTP_PROTOCOL } from '../../Config';
import BaseAPI from './BaseAPI';
import BaseAPI from './API';
class BackendAPI extends BaseAPI {
public constructor() {

View File

@ -2,6 +2,7 @@ import Color from 'Common/Types/Color';
export const Blue: Color = new Color('#7a7fdc');
export const Black: Color = new Color('#000000');
export const White: Color = new Color('#ffffff');
export const Indigo: Color = new Color('#564ab1');
export const Purple: Color = new Color('#6f42c1');
export const Pink: Color = new Color('#e83e8c');

View File

@ -24,27 +24,27 @@ export default class User {
}
public static setUserId(id: ObjectID): void {
LocalStorage.setItem('id', id.toString());
LocalStorage.setItem('user_id', id.toString());
}
public static getUserId(): ObjectID {
return new ObjectID((LocalStorage.getItem('id') as string) || '');
return new ObjectID((LocalStorage.getItem('user_id') as string) || '');
}
public static getName(): Name {
return new Name((LocalStorage.getItem('name') as string) || '');
return new Name((LocalStorage.getItem('user_name') as string) || '');
}
public static setName(name: string): void {
LocalStorage.setItem('name', name);
public static setName(name: Name): void {
LocalStorage.setItem('user_name', name.toString());
}
public static getEmail(): Email {
return new Email(LocalStorage.getItem('email') as string);
return new Email(LocalStorage.getItem('user_email') as string);
}
public static setEmail(email: Email): void {
LocalStorage.setItem('email', email);
LocalStorage.setItem('user_email', email);
}
public static initialUrl(): URL {
@ -73,7 +73,7 @@ export default class User {
}
public static removeUserId(): void {
LocalStorage.removeItem('id');
LocalStorage.removeItem('user_id');
}
public static removeAccessToken(): void {

View File

@ -17,7 +17,7 @@ import Logs from './Pages/Logs/Logs';
import Navigation from 'CommonUI/src/Utils/Navigation';
import RouteMap from './Utils/RouteMap';
import PageMap from './Utils/PageMap';
import { ACCOUNTS_URL } from 'CommonUI/src/Config';
// Settings Pages
import Settings from './Pages/Settings/Settings';
import SettingsDangerZone from './Pages/Settings/DangerZone';
@ -25,11 +25,16 @@ import SettingsApiKeys from './Pages/Settings/APIKeys';
import SettingsCreateAPIKey from './Pages/Settings/CreateAPIKey';
// Import CSS
import 'CommonUI/src/Styles/theme.scss';
import User from 'CommonUI/src/Utils/User';
const App: FunctionComponent = () => {
Navigation.setNavigateHook(useNavigate());
Navigation.setLocation(useLocation());
if (!User.isLoggedIn()) {
Navigation.navigate(ACCOUNTS_URL);
}
return (
<MasterPage>
<Routes>

View File

@ -63,5 +63,5 @@ module.exports = {
devServer: {
historyApiFallback: true,
},
devtool: 'inline-source-map',
devtool: 'eval-source-map',
}

View File

@ -46,7 +46,7 @@ router.post(
const data: JSONObject = req.body;
const user: User = User.asPublicCreateable<User>(
data['user'] as JSONObject,
data as JSONObject,
User
);

View File

@ -5,7 +5,6 @@ version: '3.7'
x-common-variables: &common-variables
IS_SAAS_SERVICE: ${IS_SAAS_SERVICE}
DEBUG: 'express:*'
services:
##IMPORTANT: