mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-25 23:54:55 +01:00
Google OAuth support
This commit is contained in:
parent
fb4568a817
commit
d7159760e8
@ -9,7 +9,7 @@ context('Render all sample maps', () => {
|
|||||||
'icon-sample',
|
'icon-sample',
|
||||||
'img-support',
|
'img-support',
|
||||||
'order',
|
'order',
|
||||||
'rel-error',
|
//'rel-error',
|
||||||
'sample1',
|
'sample1',
|
||||||
'sample2',
|
'sample2',
|
||||||
'sample3',
|
'sample3',
|
||||||
@ -24,7 +24,7 @@ context('Render all sample maps', () => {
|
|||||||
cy.reload();
|
cy.reload();
|
||||||
|
|
||||||
cy.get('svg > path').should('be.visible');
|
cy.get('svg > path').should('be.visible');
|
||||||
cy.get('[aria-label="vortex-loading"]', { timeout: 60000 }).should('not.exist');
|
cy.get('[aria-label="vortex-loading"]', { timeout: 120000 }).should('not.exist');
|
||||||
cy.matchImageSnapshot(`map-${mapId}`);
|
cy.matchImageSnapshot(`map-${mapId}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -515,5 +515,44 @@
|
|||||||
},
|
},
|
||||||
"dialog.loading": {
|
"dialog.loading": {
|
||||||
"defaultMessage": "Wird geladen ..."
|
"defaultMessage": "Wird geladen ..."
|
||||||
}
|
},
|
||||||
|
"registration.google.button": {
|
||||||
|
"defaultMessage": "Melden Sie sich bei Google an"
|
||||||
|
},
|
||||||
|
"login.google.button": {
|
||||||
|
"defaultMessage": "Anmeldung mit Google"
|
||||||
|
},
|
||||||
|
"registration.division": {
|
||||||
|
"defaultMessage": "oder"
|
||||||
|
},
|
||||||
|
"login.division": {
|
||||||
|
"defaultMessage": "oder"
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.title": {
|
||||||
|
"defaultMessage": "Bestätigen"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.title": {
|
||||||
|
"defaultMessage": "Fertigstellung ..."
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.description": {
|
||||||
|
"defaultMessage": "Ein Konto mit derselben E-Mail-Adresse wurde zuvor registriert. Möchten Sie Ihr Google-Konto mit diesem WiseMapping-Konto verknüpfen?"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.description": {
|
||||||
|
"defaultMessage": "Bitte warten Sie, während wir Ihre Identität überprüfen"
|
||||||
|
},
|
||||||
|
"registation.callback.error.message": {
|
||||||
|
"defaultMessage": "Beim Überprüfen Ihrer Identität bei Google ist ein Fehler aufgetreten. Sie können es auf der Anmeldeseite erneut versuchen"
|
||||||
|
},
|
||||||
|
"registration.callback.back": {
|
||||||
|
"defaultMessage": "Zurück zur Anmeldung"
|
||||||
|
},
|
||||||
|
"registration.callback.sync": {
|
||||||
|
"defaultMessage": "Konto synchronisieren"
|
||||||
|
},
|
||||||
|
"forgot.oauth.message": {
|
||||||
|
"defaultMessage": "Sie benötigen kein Passwort, bitte melden Sie sich mit Google an"
|
||||||
|
},
|
||||||
|
"forgot.oauth.back": {
|
||||||
|
"defaultMessage": "Zurück zur Anmeldung"
|
||||||
|
}
|
||||||
}
|
}
|
@ -188,6 +188,12 @@
|
|||||||
"forgot.email": {
|
"forgot.email": {
|
||||||
"defaultMessage": "Email"
|
"defaultMessage": "Email"
|
||||||
},
|
},
|
||||||
|
"forgot.oauth.back": {
|
||||||
|
"defaultMessage": "Back to login"
|
||||||
|
},
|
||||||
|
"forgot.oauth.message": {
|
||||||
|
"defaultMessage": "You dont need password, please login using Google."
|
||||||
|
},
|
||||||
"forgot.page-title": {
|
"forgot.page-title": {
|
||||||
"defaultMessage": "Forgot Password | WiseMapping"
|
"defaultMessage": "Forgot Password | WiseMapping"
|
||||||
},
|
},
|
||||||
@ -305,6 +311,9 @@
|
|||||||
"login.desc": {
|
"login.desc": {
|
||||||
"defaultMessage": "Log into your account"
|
"defaultMessage": "Log into your account"
|
||||||
},
|
},
|
||||||
|
"login.division": {
|
||||||
|
"defaultMessage": "or"
|
||||||
|
},
|
||||||
"login.email": {
|
"login.email": {
|
||||||
"defaultMessage": "Email"
|
"defaultMessage": "Email"
|
||||||
},
|
},
|
||||||
@ -314,6 +323,9 @@
|
|||||||
"login.forgotpwd": {
|
"login.forgotpwd": {
|
||||||
"defaultMessage": "Forgot Password ?"
|
"defaultMessage": "Forgot Password ?"
|
||||||
},
|
},
|
||||||
|
"login.google.button": {
|
||||||
|
"defaultMessage": "Sign in with Google"
|
||||||
|
},
|
||||||
"login.page-title": {
|
"login.page-title": {
|
||||||
"defaultMessage": "Login | WiseMapping"
|
"defaultMessage": "Login | WiseMapping"
|
||||||
},
|
},
|
||||||
@ -440,18 +452,45 @@
|
|||||||
"publish.title": {
|
"publish.title": {
|
||||||
"defaultMessage": "Publish"
|
"defaultMessage": "Publish"
|
||||||
},
|
},
|
||||||
|
"registation.callback.error.message": {
|
||||||
|
"defaultMessage": "An error occurred validating your identity with Google, you can try again from the login page"
|
||||||
|
},
|
||||||
"registation.success-title": {
|
"registation.success-title": {
|
||||||
"defaultMessage": "Registation Success | WiseMapping"
|
"defaultMessage": "Registation Success | WiseMapping"
|
||||||
},
|
},
|
||||||
|
"registration.callback.back": {
|
||||||
|
"defaultMessage": "Back to login"
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.description": {
|
||||||
|
"defaultMessage": "An account with the same email was previously registered. Do you want to link your google account to that WiseMapping account?"
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.title": {
|
||||||
|
"defaultMessage": "Confirm"
|
||||||
|
},
|
||||||
|
"registration.callback.sync": {
|
||||||
|
"defaultMessage": "Sync account"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.description": {
|
||||||
|
"defaultMessage": "Please wait while we validate your identity"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.title": {
|
||||||
|
"defaultMessage": "Finishing..."
|
||||||
|
},
|
||||||
"registration.desc": {
|
"registration.desc": {
|
||||||
"defaultMessage": "Signing up is free and just take a moment"
|
"defaultMessage": "Signing up is free and just take a moment"
|
||||||
},
|
},
|
||||||
|
"registration.division": {
|
||||||
|
"defaultMessage": "or"
|
||||||
|
},
|
||||||
"registration.email": {
|
"registration.email": {
|
||||||
"defaultMessage": "Email"
|
"defaultMessage": "Email"
|
||||||
},
|
},
|
||||||
"registration.firstname": {
|
"registration.firstname": {
|
||||||
"defaultMessage": "First Name"
|
"defaultMessage": "First Name"
|
||||||
},
|
},
|
||||||
|
"registration.google.button": {
|
||||||
|
"defaultMessage": "Sign up with Google"
|
||||||
|
},
|
||||||
"registration.lastname": {
|
"registration.lastname": {
|
||||||
"defaultMessage": "Last Name"
|
"defaultMessage": "Last Name"
|
||||||
},
|
},
|
||||||
|
@ -491,5 +491,44 @@
|
|||||||
},
|
},
|
||||||
"dialog.loading": {
|
"dialog.loading": {
|
||||||
"defaultMessage": "Cargando ..."
|
"defaultMessage": "Cargando ..."
|
||||||
}
|
},
|
||||||
|
"registration.google.button": {
|
||||||
|
"defaultMessage": "Regístrate con Google"
|
||||||
|
},
|
||||||
|
"login.google.button": {
|
||||||
|
"defaultMessage": "Ingresar con Google"
|
||||||
|
},
|
||||||
|
"registration.division": {
|
||||||
|
"defaultMessage": "ó"
|
||||||
|
},
|
||||||
|
"login.division": {
|
||||||
|
"defaultMessage": "ó"
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.title": {
|
||||||
|
"defaultMessage": "Confirmación"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.title": {
|
||||||
|
"defaultMessage": "Finalizando ..."
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.description": {
|
||||||
|
"defaultMessage": "Una cuenta con el mismo email fue registrada previamente. ¿Quieres asociar tu cuenta de Google con esa cuenta de WiseMapping?"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.description": {
|
||||||
|
"defaultMessage": "Por favor espera mientras validamos tu identidad"
|
||||||
|
},
|
||||||
|
"registation.callback.error.message": {
|
||||||
|
"defaultMessage": "Ocurrió un error al validar tu identidad con Google, puedes volver a intentarlo desde la página de inicio de sesión"
|
||||||
|
},
|
||||||
|
"registration.callback.back": {
|
||||||
|
"defaultMessage": "Volver"
|
||||||
|
},
|
||||||
|
"registration.callback.sync": {
|
||||||
|
"defaultMessage": "Sincronizar cuenta"
|
||||||
|
},
|
||||||
|
"forgot.oauth.message": {
|
||||||
|
"defaultMessage": "No necesitas contraseña, por favor ingresa usando Google"
|
||||||
|
},
|
||||||
|
"forgot.oauth.back": {
|
||||||
|
"defaultMessage": "Volver"
|
||||||
|
}
|
||||||
}
|
}
|
@ -518,5 +518,44 @@
|
|||||||
},
|
},
|
||||||
"dialog.loading": {
|
"dialog.loading": {
|
||||||
"defaultMessage": "Chargement ..."
|
"defaultMessage": "Chargement ..."
|
||||||
}
|
},
|
||||||
|
"registration.google.button": {
|
||||||
|
"defaultMessage": "S'inscrire avec Google"
|
||||||
|
},
|
||||||
|
"login.google.button": {
|
||||||
|
"defaultMessage": "Connectez-vous avec Google"
|
||||||
|
},
|
||||||
|
"registration.division": {
|
||||||
|
"defaultMessage": "ou"
|
||||||
|
},
|
||||||
|
"login.division": {
|
||||||
|
"defaultMessage": "ou"
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.title": {
|
||||||
|
"defaultMessage": "Confirmer"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.title": {
|
||||||
|
"defaultMessage": "Finition ..."
|
||||||
|
},
|
||||||
|
"registration.callback.confirm.description": {
|
||||||
|
"defaultMessage": "Un compte avec le même e-mail a déjà été enregistré. Voulez-vous lier votre compte Google à ce compte WiseMapping ?"
|
||||||
|
},
|
||||||
|
"registration.callback.waiting.description": {
|
||||||
|
"defaultMessage": "Veuillez patienter pendant que nous validons votre identité"
|
||||||
|
},
|
||||||
|
"registation.callback.error.message": {
|
||||||
|
"defaultMessage": "Une erreur s'est produite lors de la validation de votre identité auprès de Google, vous pouvez réessayer depuis la page de connexion"
|
||||||
|
},
|
||||||
|
"registration.callback.back": {
|
||||||
|
"defaultMessage": "Retour connexion"
|
||||||
|
},
|
||||||
|
"registration.callback.sync": {
|
||||||
|
"defaultMessage": "Compte de synchronisation"
|
||||||
|
},
|
||||||
|
"forgot.oauth.message": {
|
||||||
|
"defaultMessage": "Vous n'avez pas besoin de mot de passe, veuillez vous connecter en utilisant Google"
|
||||||
|
},
|
||||||
|
"forgot.oauth.back": {
|
||||||
|
"defaultMessage": "Retour connexion"
|
||||||
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@ import ReactGA from 'react-ga4';
|
|||||||
import AppConfig from './classes/app-config';
|
import AppConfig from './classes/app-config';
|
||||||
import withSessionExpirationHandling from './components/HOCs/withSessionExpirationHandling';
|
import withSessionExpirationHandling from './components/HOCs/withSessionExpirationHandling';
|
||||||
import RegistrationSuccessPage from './components/registration-success-page';
|
import RegistrationSuccessPage from './components/registration-success-page';
|
||||||
|
import RegistrationCallbackPage from './components/registration-callback';
|
||||||
|
|
||||||
const EditorPage = React.lazy(() => import('./components/editor-page'));
|
const EditorPage = React.lazy(() => import('./components/editor-page'));
|
||||||
const MapsPage = React.lazy(() => import('./components/maps-page'));
|
const MapsPage = React.lazy(() => import('./components/maps-page'));
|
||||||
@ -70,6 +71,7 @@ const App = (): ReactElement => {
|
|||||||
<Route path="/" element={<Redirect to="/c/login" />} />
|
<Route path="/" element={<Redirect to="/c/login" />} />
|
||||||
<Route path="/c/login" element={<LoginPage />} />
|
<Route path="/c/login" element={<LoginPage />} />
|
||||||
<Route path="/c/registration" element={<RegistationPage />} />
|
<Route path="/c/registration" element={<RegistationPage />} />
|
||||||
|
<Route path="/c/registration-google" element={<RegistrationCallbackPage />} />
|
||||||
<Route path="/c/registration-success" element={<RegistrationSuccessPage />} />
|
<Route path="/c/registration-success" element={<RegistrationSuccessPage />} />
|
||||||
<Route path="/c/forgot-password" element={<ForgotPasswordPage />} />
|
<Route path="/c/forgot-password" element={<ForgotPasswordPage />} />
|
||||||
<Route
|
<Route
|
||||||
|
@ -27,6 +27,7 @@ interface Config {
|
|||||||
recaptcha2Enabled: boolean;
|
recaptcha2Enabled: boolean;
|
||||||
recaptcha2SiteKey?: string;
|
recaptcha2SiteKey?: string;
|
||||||
clientType: 'mock' | 'rest';
|
clientType: 'mock' | 'rest';
|
||||||
|
googleOauth2Url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppConfig {
|
class _AppConfig {
|
||||||
@ -35,6 +36,7 @@ class _AppConfig {
|
|||||||
clientType: 'mock',
|
clientType: 'mock',
|
||||||
recaptcha2Enabled: true,
|
recaptcha2Enabled: true,
|
||||||
recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI',
|
recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI',
|
||||||
|
googleOauth2Url: '/c/registration-google?code=aFakeCode',
|
||||||
};
|
};
|
||||||
|
|
||||||
isDevelopEnv(): boolean {
|
isDevelopEnv(): boolean {
|
||||||
@ -73,6 +75,11 @@ class _AppConfig {
|
|||||||
return config.analyticsAccount;
|
return config.analyticsAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGoogleOauth2Url(): string | undefined {
|
||||||
|
const config = this.getInstance();
|
||||||
|
return config.googleOauth2Url;
|
||||||
|
}
|
||||||
|
|
||||||
buildClient(): Client {
|
buildClient(): Client {
|
||||||
const config = this.getInstance();
|
const config = this.getInstance();
|
||||||
let result: Client;
|
let result: Client;
|
||||||
|
@ -7,6 +7,8 @@ import Client, {
|
|||||||
MapInfo,
|
MapInfo,
|
||||||
NewUser,
|
NewUser,
|
||||||
Permission,
|
Permission,
|
||||||
|
Oauth2CallbackResult,
|
||||||
|
ForgotPasswordResult,
|
||||||
} from '..';
|
} from '..';
|
||||||
import { LocaleCode } from '../../app-i18n';
|
import { LocaleCode } from '../../app-i18n';
|
||||||
|
|
||||||
@ -17,6 +19,14 @@ class CacheDecoratorClient implements Client {
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processGoogleCallback(code: string): Promise<Oauth2CallbackResult> {
|
||||||
|
return this.client.processGoogleCallback(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmAccountSync(email: string, code: string): Promise<void> {
|
||||||
|
return this.client.confirmAccountSync(email, code);
|
||||||
|
}
|
||||||
|
|
||||||
fetchStarred(id: number): Promise<boolean> {
|
fetchStarred(id: number): Promise<boolean> {
|
||||||
return this.client.fetchStarred(id);
|
return this.client.fetchStarred(id);
|
||||||
}
|
}
|
||||||
@ -117,7 +127,7 @@ class CacheDecoratorClient implements Client {
|
|||||||
return this.client.registerNewUser(user);
|
return this.client.registerNewUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPassword(email: string): Promise<void> {
|
resetPassword(email: string): Promise<ForgotPasswordResult> {
|
||||||
return this.client.resetPassword(email);
|
return this.client.resetPassword(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +58,14 @@ export type ErrorInfo = {
|
|||||||
fields?: Map<string, string>;
|
fields?: Map<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AuthenticationType = 'GOOGLE_OAUTH2' | 'DATABASE' | 'LDAP';
|
||||||
|
|
||||||
export type AccountInfo = {
|
export type AccountInfo = {
|
||||||
firstname: string;
|
firstname: string;
|
||||||
lastname: string;
|
lastname: string;
|
||||||
email: string;
|
email: string;
|
||||||
locale?: Locale;
|
locale?: Locale;
|
||||||
|
authenticationType: AuthenticationType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Permission = {
|
export type Permission = {
|
||||||
@ -71,6 +74,16 @@ export type Permission = {
|
|||||||
role: Role;
|
role: Role;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Oauth2CallbackResult = {
|
||||||
|
email: string;
|
||||||
|
googleSync: boolean;
|
||||||
|
syncCode?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForgotPasswordResult = {
|
||||||
|
action: 'EMAIL_SENT' | 'OAUTH2_USER';
|
||||||
|
};
|
||||||
|
|
||||||
interface Client {
|
interface Client {
|
||||||
deleteAccount(): Promise<void>;
|
deleteAccount(): Promise<void>;
|
||||||
importMap(model: ImportMapInfo): Promise<number>;
|
importMap(model: ImportMapInfo): Promise<number>;
|
||||||
@ -103,7 +116,9 @@ interface Client {
|
|||||||
fetchAccountInfo(): Promise<AccountInfo>;
|
fetchAccountInfo(): Promise<AccountInfo>;
|
||||||
|
|
||||||
registerNewUser(user: NewUser): Promise<void>;
|
registerNewUser(user: NewUser): Promise<void>;
|
||||||
resetPassword(email: string): Promise<void>;
|
resetPassword(email: string): Promise<ForgotPasswordResult>;
|
||||||
|
processGoogleCallback(code: string): Promise<Oauth2CallbackResult>;
|
||||||
|
confirmAccountSync(email: string, code: string): Promise<void>;
|
||||||
|
|
||||||
fetchHistory(id: number): Promise<ChangeHistory[]>;
|
fetchHistory(id: number): Promise<ChangeHistory[]>;
|
||||||
revertHistory(id: number, cid: number): Promise<void>;
|
revertHistory(id: number, cid: number): Promise<void>;
|
||||||
|
@ -24,6 +24,8 @@ import Client, {
|
|||||||
MapInfo,
|
MapInfo,
|
||||||
NewUser,
|
NewUser,
|
||||||
Permission,
|
Permission,
|
||||||
|
Oauth2CallbackResult,
|
||||||
|
ForgotPasswordResult,
|
||||||
} from '..';
|
} from '..';
|
||||||
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
||||||
|
|
||||||
@ -204,6 +206,7 @@ class MockClient implements Client {
|
|||||||
lastname: 'Fulanito',
|
lastname: 'Fulanito',
|
||||||
email: 'test@example.com',
|
email: 'test@example.com',
|
||||||
locale: localeFromStr(locale),
|
locale: localeFromStr(locale),
|
||||||
|
authenticationType: 'DATABASE',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,8 +405,30 @@ class MockClient implements Client {
|
|||||||
return Promise.resolve(this.maps);
|
return Promise.resolve(this.maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPassword(email: string): Promise<void> {
|
resetPassword(email: string): Promise<ForgotPasswordResult> {
|
||||||
console.log('email:' + email);
|
console.log('email:' + email);
|
||||||
|
return Promise.resolve({ action: 'EMAIL_SENT' });
|
||||||
|
}
|
||||||
|
|
||||||
|
processGoogleCallback(): Promise<Oauth2CallbackResult> {
|
||||||
|
// artificial delay for more realistic mock experience
|
||||||
|
const handler = (success: (result: Oauth2CallbackResult) => void) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
success({
|
||||||
|
email: 'test@email.com',
|
||||||
|
// -- use case 1) user must confirm if he wants to link accounts
|
||||||
|
// googleSync: false,
|
||||||
|
// syncCode: "834580239598234650234578"
|
||||||
|
// -- use case 2) user already confirmed
|
||||||
|
googleSync: true,
|
||||||
|
syncCode: undefined,
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
return new Promise(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmAccountSync(): Promise<void> {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import Client, {
|
|||||||
AccountInfo,
|
AccountInfo,
|
||||||
ImportMapInfo,
|
ImportMapInfo,
|
||||||
Permission,
|
Permission,
|
||||||
|
Oauth2CallbackResult,
|
||||||
|
ForgotPasswordResult,
|
||||||
} from '..';
|
} from '..';
|
||||||
import { getCsrfToken } from '../../../utils';
|
import { getCsrfToken } from '../../../utils';
|
||||||
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
||||||
@ -262,6 +264,7 @@ export default class RestClient implements Client {
|
|||||||
firstname: account.firstname ? account.firstname : '',
|
firstname: account.firstname ? account.firstname : '',
|
||||||
email: account.email,
|
email: account.email,
|
||||||
locale: locale ? localeFromStr(locale) : undefined,
|
locale: locale ? localeFromStr(locale) : undefined,
|
||||||
|
authenticationType: account.authenticationType,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -472,8 +475,11 @@ export default class RestClient implements Client {
|
|||||||
return new Promise(handler);
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPassword(email: string): Promise<void> {
|
resetPassword(email: string): Promise<ForgotPasswordResult> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (
|
||||||
|
success: (result: ForgotPasswordResult) => void,
|
||||||
|
reject: (error: ErrorInfo) => void,
|
||||||
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(
|
.put(
|
||||||
`${this.baseUrl}/service/users/resetPassword?email=${encodeURIComponent(email)}`,
|
`${this.baseUrl}/service/users/resetPassword?email=${encodeURIComponent(email)}`,
|
||||||
@ -482,9 +488,9 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then((response) => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, lets return if an email was sent or the user should login with oauth
|
||||||
success();
|
success({ action: response.data.action });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const response = error.response;
|
const response = error.response;
|
||||||
@ -628,6 +634,47 @@ export default class RestClient implements Client {
|
|||||||
return new Promise(handler);
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processGoogleCallback(code: string): Promise<Oauth2CallbackResult> {
|
||||||
|
const handler = (
|
||||||
|
success: (result: Oauth2CallbackResult) => void,
|
||||||
|
reject: (error: ErrorInfo) => void,
|
||||||
|
) => {
|
||||||
|
this.axios
|
||||||
|
.post(`${this.baseUrl}/service/oauth2/googlecallback?code=${code}`, {
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
success({
|
||||||
|
email: response.data.email,
|
||||||
|
googleSync: response.data.googleSync,
|
||||||
|
syncCode: response.data.syncCode,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
|
reject(errorInfo);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return new Promise(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmAccountSync(email: string, code: string): Promise<void> {
|
||||||
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
|
this.axios
|
||||||
|
.put(`${this.baseUrl}/service/oauth2/confirmaccountsync?email=${email}&code=${code}`, {
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
success();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
|
reject(errorInfo);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return new Promise(handler);
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private parseResponseOnError = (response: any): ErrorInfo => {
|
private parseResponseOnError = (response: any): ErrorInfo => {
|
||||||
console.error(`Performing backend action error: ${JSON.stringify(response)}`);
|
console.error(`Performing backend action error: ${JSON.stringify(response)}`);
|
||||||
|
@ -383,6 +383,18 @@
|
|||||||
"value": "E-Mail"
|
"value": "E-Mail"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"forgot.oauth.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Zurück zur Anmeldung"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"forgot.oauth.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Sie benötigen kein Passwort, bitte melden Sie sich mit Google an"
|
||||||
|
}
|
||||||
|
],
|
||||||
"forgot.page-title": [
|
"forgot.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -615,6 +627,12 @@
|
|||||||
"value": "Melde dich mit deinem Konto an"
|
"value": "Melde dich mit deinem Konto an"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "oder"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.email": [
|
"login.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -633,6 +651,12 @@
|
|||||||
"value": "Passwort vergessen?"
|
"value": "Passwort vergessen?"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Anmeldung mit Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.hsqldbcofig": [
|
"login.hsqldbcofig": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -903,18 +927,66 @@
|
|||||||
"value": "Veröffentlichen"
|
"value": "Veröffentlichen"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registation.callback.error.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Beim Überprüfen Ihrer Identität bei Google ist ein Fehler aufgetreten. Sie können es auf der Anmeldeseite erneut versuchen"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registation.success-title": [
|
"registation.success-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Registrierung erfolgreich | WiseMapping"
|
"value": "Registrierung erfolgreich | WiseMapping"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.callback.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Zurück zur Anmeldung"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Ein Konto mit derselben E-Mail-Adresse wurde zuvor registriert. Möchten Sie Ihr Google-Konto mit diesem WiseMapping-Konto verknüpfen?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Bestätigen"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.sync": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Konto synchronisieren"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Bitte warten Sie, während wir Ihre Identität überprüfen"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Fertigstellung ..."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Nimm dir einen Moment Zeit. Die Anmeldung ist kostenlos."
|
"value": "Nimm dir einen Moment Zeit. Die Anmeldung ist kostenlos."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "oder"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.email": [
|
"registration.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -927,6 +999,12 @@
|
|||||||
"value": "Vorname"
|
"value": "Vorname"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Melden Sie sich bei Google an"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.lastname": [
|
"registration.lastname": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -377,6 +377,18 @@
|
|||||||
"value": "Email"
|
"value": "Email"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"forgot.oauth.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Back to login"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"forgot.oauth.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "You dont need password, please login using Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"forgot.page-title": [
|
"forgot.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -637,6 +649,12 @@
|
|||||||
"value": "Forgot Password ?"
|
"value": "Forgot Password ?"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Sign in with Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.page-title": [
|
"login.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -901,18 +919,66 @@
|
|||||||
"value": "Publish"
|
"value": "Publish"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registation.callback.error.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "An error occurred validating your identity with Google, you can try again from the login page"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registation.success-title": [
|
"registation.success-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Registation Success | WiseMapping"
|
"value": "Registation Success | WiseMapping"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.callback.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Back to login"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "An account with the same email was previously registered. Do you want to link your google account to that WiseMapping account?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Confirm"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.sync": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Sync account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Please wait while we validate your identity"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Finishing ..."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Signing up is free and just take a moment"
|
"value": "Signing up is free and just take a moment"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "or"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.email": [
|
"registration.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -925,6 +991,12 @@
|
|||||||
"value": "First Name"
|
"value": "First Name"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Sign up with Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.lastname": [
|
"registration.lastname": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -377,6 +377,18 @@
|
|||||||
"value": "Correo electrónico"
|
"value": "Correo electrónico"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"forgot.oauth.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Volver"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"forgot.oauth.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "No necesitas contraseña, por favor ingresa usando Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"forgot.page-title": [
|
"forgot.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -561,6 +573,12 @@
|
|||||||
"value": "Ingrese a su cuenta"
|
"value": "Ingrese a su cuenta"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "ó"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.email": [
|
"login.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -579,6 +597,12 @@
|
|||||||
"value": "Has olvidado tu contraseña ?"
|
"value": "Has olvidado tu contraseña ?"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Ingresar con Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.hsqldbcofig": [
|
"login.hsqldbcofig": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -849,18 +873,66 @@
|
|||||||
"value": "Publicar"
|
"value": "Publicar"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registation.callback.error.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Ocurrió un error al validar tu identidad con Google, puedes volver a intentarlo desde la página de inicio de sesión"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registation.success-title": [
|
"registation.success-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Éxito de registro | WiseMapping"
|
"value": "Éxito de registro | WiseMapping"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.callback.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Volver"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Una cuenta con el mismo email fue registrada previamente. ¿Quieres asociar tu cuenta de Google con esa cuenta de WiseMapping?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Confirmación"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.sync": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Sincronizar cuenta"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Por favor espera mientras validamos tu identidad"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Finalizando ..."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Registrarse es gratis y solo tómese un momento"
|
"value": "Registrarse es gratis y solo tómese un momento"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "ó"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.email": [
|
"registration.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -873,6 +945,12 @@
|
|||||||
"value": "Primer nombre"
|
"value": "Primer nombre"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Regístrate con Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.lastname": [
|
"registration.lastname": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -375,6 +375,18 @@
|
|||||||
"value": "E-mail"
|
"value": "E-mail"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"forgot.oauth.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Retour connexion"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"forgot.oauth.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Vous n'avez pas besoin de mot de passe, veuillez vous connecter en utilisant Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"forgot.page-title": [
|
"forgot.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -607,6 +619,12 @@
|
|||||||
"value": "Connectez-vous à votre compte"
|
"value": "Connectez-vous à votre compte"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "ou"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.email": [
|
"login.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -625,6 +643,12 @@
|
|||||||
"value": "Mot de passe oublié ?"
|
"value": "Mot de passe oublié ?"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Connectez-vous avec Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.hsqldbcofig": [
|
"login.hsqldbcofig": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -895,18 +919,66 @@
|
|||||||
"value": "Publier"
|
"value": "Publier"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registation.callback.error.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Une erreur s'est produite lors de la validation de votre identité auprès de Google, vous pouvez réessayer depuis la page de connexion"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registation.success-title": [
|
"registation.success-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Inscription réussie | WiseMapping"
|
"value": "Inscription réussie | WiseMapping"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.callback.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Retour connexion"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Un compte avec le même e-mail a déjà été enregistré. Voulez-vous lier votre compte Google à ce compte WiseMapping ?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Confirmer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.sync": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Compte de synchronisation"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Veuillez patienter pendant que nous validons votre identité"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Finition ..."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "L'inscription est gratuite et ne prends qu'un instant"
|
"value": "L'inscription est gratuite et ne prends qu'un instant"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "ou"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.email": [
|
"registration.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -919,6 +991,12 @@
|
|||||||
"value": "Prénom"
|
"value": "Prénom"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "S'inscrire avec Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.lastname": [
|
"registration.lastname": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -371,6 +371,18 @@
|
|||||||
"value": "Email"
|
"value": "Email"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"forgot.oauth.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Вернуться на страницу авторизации"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"forgot.oauth.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Вам не нужен пароль, пожалуйста, войдите с помощью Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"forgot.page-title": [
|
"forgot.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -555,6 +567,12 @@
|
|||||||
"value": "Войдите в свой аккаунт"
|
"value": "Войдите в свой аккаунт"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "или же"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.email": [
|
"login.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -573,6 +591,12 @@
|
|||||||
"value": "Забыли пароль?"
|
"value": "Забыли пароль?"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Войти через Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.hsqldbcofig": [
|
"login.hsqldbcofig": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -843,18 +867,66 @@
|
|||||||
"value": "Опубликовать"
|
"value": "Опубликовать"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registation.callback.error.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Произошла ошибка при подтверждении вашей личности в Google. Повторите попытку со страницы входа."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registation.success-title": [
|
"registation.success-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Успешная регистрация | WiseMapping"
|
"value": "Успешная регистрация | WiseMapping"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.callback.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Вернуться на страницу авторизации"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Учетная запись c таким же адресом электронной почты была ранее зарегистрирована. Вы хотите связать свою учетную запись Google с этой учетной записью WiseMapping?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Подтверждать"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.sync": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Синхронизировать учетную запись"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Подождите, пока мы подтвердим вашу личность"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Отделка ..."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Регистрация бесплатна и займет всего минуту"
|
"value": "Регистрация бесплатна и займет всего минуту"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "или же"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.email": [
|
"registration.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -867,6 +939,12 @@
|
|||||||
"value": "Имя"
|
"value": "Имя"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Зарегистрируйтесь в Google"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.lastname": [
|
"registration.lastname": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -371,6 +371,18 @@
|
|||||||
"value": "电子邮件"
|
"value": "电子邮件"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"forgot.oauth.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "回到登入"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"forgot.oauth.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "您不需要密码,请使用谷歌登录"
|
||||||
|
}
|
||||||
|
],
|
||||||
"forgot.page-title": [
|
"forgot.page-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -603,6 +615,12 @@
|
|||||||
"value": "登录您的账号"
|
"value": "登录您的账号"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "或者"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.email": [
|
"login.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -621,6 +639,12 @@
|
|||||||
"value": "忘记密码?"
|
"value": "忘记密码?"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"login.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "使用 Google 登錄"
|
||||||
|
}
|
||||||
|
],
|
||||||
"login.hsqldbcofig": [
|
"login.hsqldbcofig": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -891,18 +915,66 @@
|
|||||||
"value": "发布"
|
"value": "发布"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registation.callback.error.message": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "使用 Google 验证您的身份时出错,您可以从登录页面重试"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registation.success-title": [
|
"registation.success-title": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "注册成功|WiseMapping"
|
"value": "注册成功|WiseMapping"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.callback.back": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "回到登入"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "之前注册了一个具有相同电子邮件地址的帐户。你想将你的谷歌账户链接到那个 WiseMapping 账户吗?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.confirm.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "确认"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.sync": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "同步账户"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.description": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "我们正在验证您的身份,请稍候"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registration.callback.waiting.title": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "整理 ..."
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "注册免费,分分钟就好"
|
"value": "注册免费,分分钟就好"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.division": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "或者"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.email": [
|
"registration.email": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -915,6 +987,12 @@
|
|||||||
"value": "名字"
|
"value": "名字"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"registration.google.button": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "註冊谷歌"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.lastname": [
|
"registration.lastname": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
|
import { Button } from '@mui/material';
|
||||||
|
import GoogleIcon from '../google-icon';
|
||||||
|
|
||||||
|
const googleButtonStyle = css({
|
||||||
|
color: '#000000',
|
||||||
|
fontWeight: '300',
|
||||||
|
border: '1px solid black',
|
||||||
|
'&:hover': {
|
||||||
|
border: '1px solid black',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
type GoogleButtonProps = {
|
||||||
|
text: string;
|
||||||
|
onClick: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GoogleButton: React.FunctionComponent<GoogleButtonProps> = ({
|
||||||
|
text,
|
||||||
|
onClick,
|
||||||
|
}: GoogleButtonProps) => {
|
||||||
|
return (
|
||||||
|
<Button variant="outlined" css={googleButtonStyle} startIcon={GoogleIcon} onClick={onClick}>
|
||||||
|
{text}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GoogleButton;
|
31
packages/webapp/src/components/common/google-icon/index.tsx
Normal file
31
packages/webapp/src/components/common/google-icon/index.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SvgIcon } from '@mui/material';
|
||||||
|
|
||||||
|
const GoogleIconSvg = () => {
|
||||||
|
return (
|
||||||
|
<SvgIcon>
|
||||||
|
<g transform="matrix(1, 0, 0, 1, 27.009001, -39.238998)">
|
||||||
|
<path
|
||||||
|
fill="#4285F4"
|
||||||
|
d="M -3.264 51.509 C -3.264 50.719 -3.334 49.969 -3.454 49.239 L -14.754 49.239 L -14.754 53.749 L -8.284 53.749 C -8.574 55.229 -9.424 56.479 -10.684 57.329 L -10.684 60.329 L -6.824 60.329 C -4.564 58.239 -3.264 55.159 -3.264 51.509 Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#34A853"
|
||||||
|
d="M -14.754 63.239 C -11.514 63.239 -8.804 62.159 -6.824 60.329 L -10.684 57.329 C -11.764 58.049 -13.134 58.489 -14.754 58.489 C -17.884 58.489 -20.534 56.379 -21.484 53.529 L -25.464 53.529 L -25.464 56.619 C -23.494 60.539 -19.444 63.239 -14.754 63.239 Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#FBBC05"
|
||||||
|
d="M -21.484 53.529 C -21.734 52.809 -21.864 52.039 -21.864 51.239 C -21.864 50.439 -21.724 49.669 -21.484 48.949 L -21.484 45.859 L -25.464 45.859 C -26.284 47.479 -26.754 49.299 -26.754 51.239 C -26.754 53.179 -26.284 54.999 -25.464 56.619 L -21.484 53.529 Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#EA4335"
|
||||||
|
d="M -14.754 43.989 C -12.984 43.989 -11.404 44.599 -10.154 45.789 L -6.734 42.369 C -8.804 40.429 -11.514 39.239 -14.754 39.239 C -19.444 39.239 -23.494 41.939 -25.464 45.859 L -21.484 48.949 C -20.534 46.099 -17.884 43.989 -14.754 43.989 Z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</SvgIcon>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const GoogleIcon = <GoogleIconSvg />;
|
||||||
|
|
||||||
|
export default GoogleIcon;
|
29
packages/webapp/src/components/common/separator/index.tsx
Normal file
29
packages/webapp/src/components/common/separator/index.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import { containerStyle, lineStyle, textStyle } from './style';
|
||||||
|
|
||||||
|
type SeparatorProps = {
|
||||||
|
responsive: boolean;
|
||||||
|
text: string;
|
||||||
|
maxWidth?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Separator: React.FunctionComponent<SeparatorProps> = ({
|
||||||
|
responsive,
|
||||||
|
text,
|
||||||
|
maxWidth = undefined,
|
||||||
|
}: SeparatorProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
// eslint-disable-next-line react/no-unknown-property
|
||||||
|
<div css={containerStyle(responsive, maxWidth, theme.breakpoints.down('md'))}>
|
||||||
|
{/* eslint-disable-next-line react/no-unknown-property */}
|
||||||
|
<div css={lineStyle(responsive, theme.breakpoints.up('md'))}></div>
|
||||||
|
{/* eslint-disable-next-line react/no-unknown-property */}
|
||||||
|
<div css={textStyle(responsive, theme.breakpoints.up('md'))}>{text}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Separator;
|
73
packages/webapp/src/components/common/separator/style.ts
Normal file
73
packages/webapp/src/components/common/separator/style.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { css, SerializedStyles } from '@emotion/react';
|
||||||
|
|
||||||
|
export const containerStyle = (
|
||||||
|
responsive: boolean,
|
||||||
|
maxWidth: number,
|
||||||
|
breakPointDownMd: string,
|
||||||
|
): SerializedStyles => {
|
||||||
|
return css([
|
||||||
|
{
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
|
height: '90%',
|
||||||
|
top: '5%',
|
||||||
|
display: 'inline-block',
|
||||||
|
},
|
||||||
|
responsive && {
|
||||||
|
[breakPointDownMd]: {
|
||||||
|
paddingTop: '25px',
|
||||||
|
paddingBottom: '25px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
!responsive && {
|
||||||
|
paddingTop: '25px',
|
||||||
|
paddingBottom: '25px',
|
||||||
|
},
|
||||||
|
maxWidth && {
|
||||||
|
maxWidth: maxWidth,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lineStyle = (responsive: boolean, breakPointUpMd: string): SerializedStyles => {
|
||||||
|
return css([
|
||||||
|
{
|
||||||
|
backgroundColor: '#dce2e6',
|
||||||
|
position: 'absolute',
|
||||||
|
left: '50%',
|
||||||
|
height: '1px',
|
||||||
|
width: '100%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
},
|
||||||
|
responsive && {
|
||||||
|
[breakPointUpMd]: {
|
||||||
|
height: '100%',
|
||||||
|
width: '1px',
|
||||||
|
transform: 'translateX(0%) translateY(0%)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const textStyle = (responsive: boolean, breakPointUpMd: string): SerializedStyles => {
|
||||||
|
return css([
|
||||||
|
{
|
||||||
|
backgroundColor: '#DCE2E6',
|
||||||
|
padding: '5px 10px',
|
||||||
|
minWidth: '36px',
|
||||||
|
borderRadius: '18px',
|
||||||
|
fontSize: '18px',
|
||||||
|
color: 'white',
|
||||||
|
textAlign: 'center',
|
||||||
|
display: 'inline-block',
|
||||||
|
position: 'absolute',
|
||||||
|
transform: 'translateX(-50%) translateY(-50%)',
|
||||||
|
left: '50%',
|
||||||
|
},
|
||||||
|
responsive && {
|
||||||
|
[breakPointUpMd]: {
|
||||||
|
top: '15%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl';
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import Client, { ErrorInfo } from '../../classes/client';
|
import Client, { ErrorInfo, ForgotPasswordResult } from '../../classes/client';
|
||||||
|
|
||||||
import Header from '../layout/header';
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer';
|
import Footer from '../layout/footer';
|
||||||
@ -12,22 +12,28 @@ import Input from '../form/input';
|
|||||||
import GlobalError from '../form/global-error';
|
import GlobalError from '../form/global-error';
|
||||||
import SubmitButton from '../form/submit-button';
|
import SubmitButton from '../form/submit-button';
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { getCsrfToken, getCsrfTokenParameter } from '../../utils';
|
import { getCsrfToken, getCsrfTokenParameter } from '../../utils';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Button } from '@mui/material';
|
||||||
|
|
||||||
const ForgotPassword = () => {
|
const ForgotPassword = () => {
|
||||||
const [email, setEmail] = useState<string>('');
|
const [email, setEmail] = useState<string>('');
|
||||||
const [error, setError] = useState<ErrorInfo>();
|
const [error, setError] = useState<ErrorInfo>();
|
||||||
|
const [showOauthMessage, setShowOauthMessage] = useState<boolean>(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const service: Client = useSelector(activeInstance);
|
const service: Client = useSelector(activeInstance);
|
||||||
const mutation = useMutation<void, ErrorInfo, string>(
|
const mutation = useMutation<ForgotPasswordResult, ErrorInfo, string>(
|
||||||
(email: string) => service.resetPassword(email),
|
(email: string) => service.resetPassword(email),
|
||||||
{
|
{
|
||||||
onSuccess: () => navigate('/c/forgot-password-success'),
|
onSuccess: (result) => {
|
||||||
|
if (result.action === 'EMAIL_SENT') navigate('/c/forgot-password-success');
|
||||||
|
if (result.action === 'OAUTH2_USER') setShowOauthMessage(true);
|
||||||
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error);
|
setError(error);
|
||||||
},
|
},
|
||||||
@ -39,6 +45,29 @@ const ForgotPassword = () => {
|
|||||||
mutation.mutate(email);
|
mutation.mutate(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (showOauthMessage) {
|
||||||
|
return (
|
||||||
|
<FormContainer>
|
||||||
|
<Typography>
|
||||||
|
<FormattedMessage
|
||||||
|
id="forgot.oauth.message"
|
||||||
|
defaultMessage="You dont need password, please login using Google."
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
size="medium"
|
||||||
|
variant="contained"
|
||||||
|
component={RouterLink}
|
||||||
|
to="/c/login"
|
||||||
|
disableElevation={true}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="forgot.oauth.back" defaultMessage="Back to login" />
|
||||||
|
</Button>
|
||||||
|
</FormContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer>
|
<FormContainer>
|
||||||
<Typography variant="h4" component="h1">
|
<Typography variant="h4" component="h1">
|
||||||
|
@ -24,7 +24,7 @@ const SubmitButton = (props: SubmitButton): React.ReactElement => {
|
|||||||
disableElevation={true}
|
disableElevation={true}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
style={{
|
style={{
|
||||||
width: '350px',
|
width: '300px',
|
||||||
height: '53px',
|
height: '53px',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
margin: '7px 0px',
|
margin: '7px 0px',
|
||||||
|
@ -8,6 +8,7 @@ export const StyledFooter = styled.footer`
|
|||||||
background-color: #f9a826;
|
background-color: #f9a826;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 200px 1fr 1fr 1fr 3fr;
|
grid-template-columns: 200px 1fr 1fr 1fr 3fr;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
& a {
|
& a {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -12,6 +12,9 @@ import FormControl from '@mui/material/FormControl';
|
|||||||
import Link from '@mui/material/Link';
|
import Link from '@mui/material/Link';
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import { getCsrfToken, getCsrfTokenParameter } from '../../utils';
|
import { getCsrfToken, getCsrfTokenParameter } from '../../utils';
|
||||||
|
import Separator from '../common/separator';
|
||||||
|
import GoogleButton from '../common/google-button';
|
||||||
|
import AppConfig from '../../classes/app-config';
|
||||||
|
|
||||||
const LoginError = () => {
|
const LoginError = () => {
|
||||||
// @Todo: This must be reviewed to be based on navigation state.
|
// @Todo: This must be reviewed to be based on navigation state.
|
||||||
@ -32,7 +35,7 @@ const LoginError = () => {
|
|||||||
default:
|
default:
|
||||||
msg = intl.formatMessage({
|
msg = intl.formatMessage({
|
||||||
id: 'login.error',
|
id: 'login.error',
|
||||||
defaultMessage: 'The email address or password you entered is not valid.',
|
defaultMessage: 'The email address or password you entered is not valid.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,7 +57,7 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
<div>
|
<div>
|
||||||
<Header type="only-signup" />
|
<Header type="only-signup" />
|
||||||
|
|
||||||
<FormContainer maxWidth="xs">
|
<FormContainer>
|
||||||
<Typography variant="h4" component="h1">
|
<Typography variant="h4" component="h1">
|
||||||
<FormattedMessage id="login.title" defaultMessage="Welcome" />
|
<FormattedMessage id="login.title" defaultMessage="Welcome" />
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -102,10 +105,25 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<Link component={RouterLink} to="/c/forgot-password">
|
<Link component={RouterLink} to="/c/forgot-password">
|
||||||
<FormattedMessage id="login.forgotpwd" defaultMessage="Forgot Password ?" />
|
<FormattedMessage id="login.forgotpwd" defaultMessage="Forgot Password ?" />
|
||||||
</Link>
|
</Link>
|
||||||
|
<Separator
|
||||||
|
responsive={false}
|
||||||
|
text={intl.formatMessage({
|
||||||
|
id: 'login.division',
|
||||||
|
defaultMessage: 'or',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<GoogleButton
|
||||||
|
text={intl.formatMessage({
|
||||||
|
id: 'login.google.button',
|
||||||
|
defaultMessage: 'Sign in with Google',
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
window.location.href = AppConfig.getGoogleOauth2Url();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
@ -71,16 +71,18 @@ const AccountMenu = (): React.ReactElement => {
|
|||||||
<FormattedMessage id="menu.account" defaultMessage="Account" />
|
<FormattedMessage id="menu.account" defaultMessage="Account" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem
|
{account?.authenticationType !== 'GOOGLE_OAUTH2' && (
|
||||||
onClick={() => {
|
<MenuItem
|
||||||
handleClose(), setAction('change-password');
|
onClick={() => {
|
||||||
}}
|
handleClose(), setAction('change-password');
|
||||||
>
|
}}
|
||||||
<ListItemIcon>
|
>
|
||||||
<LockOpenOutlined fontSize="small" />
|
<ListItemIcon>
|
||||||
</ListItemIcon>
|
<LockOpenOutlined fontSize="small" />
|
||||||
<FormattedMessage id="menu.change-password" defaultMessage="Change password" />
|
</ListItemIcon>
|
||||||
</MenuItem>
|
<FormattedMessage id="menu.change-password" defaultMessage="Change password" />
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
|
||||||
<MenuItem onClick={handleClose}>
|
<MenuItem onClick={handleClose}>
|
||||||
<form action="/c/logout" method="POST" id="logoutFrom"></form>
|
<form action="/c/logout" method="POST" id="logoutFrom"></form>
|
||||||
|
159
packages/webapp/src/components/registration-callback/index.tsx
Normal file
159
packages/webapp/src/components/registration-callback/index.tsx
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
import FormContainer from '../layout/form-container';
|
||||||
|
import Header from '../layout/header';
|
||||||
|
import Footer from '../layout/footer';
|
||||||
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import ReactGA from 'react-ga4';
|
||||||
|
import Client, { Oauth2CallbackResult } from '../../classes/client';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { activeInstance } from '../../redux/clientSlice';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { CircularProgress } from '@mui/material';
|
||||||
|
import GlobalError from '../form/global-error';
|
||||||
|
import { buttonsStyle } from './style';
|
||||||
|
|
||||||
|
const RegistrationCallbackPage = (): React.ReactElement => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const client: Client = useSelector(activeInstance);
|
||||||
|
|
||||||
|
const [showError, setShowError] = useState(false);
|
||||||
|
const [callbackResult, setCallbackResult] = useState<Oauth2CallbackResult>(undefined);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = intl.formatMessage({
|
||||||
|
id: 'registation.success-title',
|
||||||
|
defaultMessage: 'Registation Success | WiseMapping',
|
||||||
|
});
|
||||||
|
ReactGA.send({
|
||||||
|
hitType: 'pageview',
|
||||||
|
page: window.location.pathname,
|
||||||
|
title: 'Registration:Success',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const googleOauthCode = new URLSearchParams(window.location.search).get('code');
|
||||||
|
client
|
||||||
|
.processGoogleCallback(googleOauthCode)
|
||||||
|
.then((result) => {
|
||||||
|
if (result.googleSync) {
|
||||||
|
// if service reports that user already has sync accounts, go to maps page
|
||||||
|
navigate('/c/maps');
|
||||||
|
}
|
||||||
|
setCallbackResult(result);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('ERROR', error);
|
||||||
|
setShowError(true);
|
||||||
|
window.newrelic?.noticeError(error);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const confirmAccountSynching = () => {
|
||||||
|
client
|
||||||
|
.confirmAccountSync(callbackResult.email, callbackResult.syncCode)
|
||||||
|
.then(() => {
|
||||||
|
navigate('/c/maps');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('ERROR', error);
|
||||||
|
window.newrelic?.noticeError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// if service reports that user doesnt sync accounts yet, we need to show the options
|
||||||
|
const needConfirmLinking = !showError && callbackResult?.email && !callbackResult?.googleSync;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header type="none" />
|
||||||
|
<FormContainer>
|
||||||
|
<Typography variant="h4" component="h1">
|
||||||
|
{needConfirmLinking ? (
|
||||||
|
<FormattedMessage id="registration.callback.confirm.title" defaultMessage="Confirm" />
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id="registration.callback.waiting.title"
|
||||||
|
defaultMessage="Finishing..."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph>
|
||||||
|
{needConfirmLinking ? (
|
||||||
|
<FormattedMessage
|
||||||
|
id="registration.callback.confirm.description"
|
||||||
|
defaultMessage="An account with the same email was previously registered. Do you want to link your google account to that WiseMapping account?"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id="registration.callback.waiting.description"
|
||||||
|
defaultMessage="Please wait while we validate your identity"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{showError && (
|
||||||
|
<>
|
||||||
|
<GlobalError
|
||||||
|
error={{
|
||||||
|
msg: intl.formatMessage({
|
||||||
|
id: 'registation.callback.error.message',
|
||||||
|
defaultMessage:
|
||||||
|
'An error occurred validating your identity with Google, you can try again from the login page',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
size="medium"
|
||||||
|
variant="contained"
|
||||||
|
component={RouterLink}
|
||||||
|
to="/c/login"
|
||||||
|
disableElevation={true}
|
||||||
|
css={buttonsStyle}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="registration.callback.back" defaultMessage="Back to login" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!needConfirmLinking && !showError && <CircularProgress />}
|
||||||
|
|
||||||
|
{needConfirmLinking && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
size="medium"
|
||||||
|
variant="contained"
|
||||||
|
component={RouterLink}
|
||||||
|
to="/c/login"
|
||||||
|
disableElevation={true}
|
||||||
|
css={buttonsStyle}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="registration.callback.back" defaultMessage="Back to login" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
confirmAccountSynching();
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
size="medium"
|
||||||
|
variant="contained"
|
||||||
|
disableElevation={true}
|
||||||
|
css={buttonsStyle}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="registration.callback.sync" defaultMessage="Sync account" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</FormContainer>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RegistrationCallbackPage;
|
@ -0,0 +1,6 @@
|
|||||||
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
export const buttonsStyle = css({
|
||||||
|
marginLeft: '10px',
|
||||||
|
marginRight: '10px',
|
||||||
|
});
|
@ -3,7 +3,6 @@ import { FormattedMessage, useIntl } from 'react-intl';
|
|||||||
import ReCAPTCHA from 'react-google-recaptcha';
|
import ReCAPTCHA from 'react-google-recaptcha';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import Client, { ErrorInfo } from '../../classes/client';
|
import Client, { ErrorInfo } from '../../classes/client';
|
||||||
import FormContainer from '../layout/form-container';
|
|
||||||
|
|
||||||
import Header from '../layout/header';
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer';
|
import Footer from '../layout/footer';
|
||||||
@ -18,6 +17,11 @@ import Typography from '@mui/material/Typography';
|
|||||||
import FormControl from '@mui/material/FormControl';
|
import FormControl from '@mui/material/FormControl';
|
||||||
import AppConfig from '../../classes/app-config';
|
import AppConfig from '../../classes/app-config';
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
|
import Separator from '../common/separator';
|
||||||
|
import GoogleButton from '../common/google-button';
|
||||||
|
import { Grid, Link } from '@mui/material';
|
||||||
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
import { recaptchaContainerStyle } from './style';
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
email: string;
|
email: string;
|
||||||
@ -28,6 +32,7 @@ export type Model = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const defaultModel: Model = { email: '', lastname: '', firstname: '', password: '', recaptcha: '' };
|
const defaultModel: Model = { email: '', lastname: '', firstname: '', password: '', recaptcha: '' };
|
||||||
|
|
||||||
const RegistrationForm = () => {
|
const RegistrationForm = () => {
|
||||||
const [model, setModel] = useState<Model>(defaultModel);
|
const [model, setModel] = useState<Model>(defaultModel);
|
||||||
const [error, setError] = useState<ErrorInfo>();
|
const [error, setError] = useState<ErrorInfo>();
|
||||||
@ -61,99 +66,130 @@ const RegistrationForm = () => {
|
|||||||
setModel({ ...model, [name as keyof Model]: value });
|
setModel({ ...model, [name as keyof Model]: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const maxFormWidth = 350;
|
||||||
|
|
||||||
|
const handleRegisterWithGoogleClick = () => {
|
||||||
|
window.location.href = AppConfig.getGoogleOauth2Url();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer>
|
<Grid container justifyContent="center">
|
||||||
<Typography variant="h4" component="h1">
|
<Grid container spacing={0} justifyContent="center" alignItems="scretch" textAlign="center">
|
||||||
<FormattedMessage id="registration.title" defaultMessage="Become a member" />
|
<Grid item md={5} xs={12} justifyContent="center">
|
||||||
</Typography>
|
<Typography variant="h4" component="h1">
|
||||||
|
<FormattedMessage id="registration.title" defaultMessage="Become a member" />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<Typography paragraph>
|
<Typography paragraph>
|
||||||
<FormattedMessage
|
|
||||||
id="registration.desc"
|
|
||||||
defaultMessage="Signing up is free and just take a moment "
|
|
||||||
/>
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<FormControl>
|
|
||||||
<form onSubmit={handleOnSubmit}>
|
|
||||||
<GlobalError error={error} />
|
|
||||||
|
|
||||||
<Input
|
|
||||||
name="email"
|
|
||||||
type="email"
|
|
||||||
onChange={handleOnChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
id: 'registration.email',
|
|
||||||
defaultMessage: 'Email',
|
|
||||||
})}
|
|
||||||
autoComplete="email"
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Input
|
|
||||||
name="firstname"
|
|
||||||
type="text"
|
|
||||||
onChange={handleOnChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
id: 'registration.firstname',
|
|
||||||
defaultMessage: 'First Name',
|
|
||||||
})}
|
|
||||||
autoComplete="given-name"
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Input
|
|
||||||
name="lastname"
|
|
||||||
type="text"
|
|
||||||
onChange={handleOnChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
id: 'registration.lastname',
|
|
||||||
defaultMessage: 'Last Name',
|
|
||||||
})}
|
|
||||||
autoComplete="family-name"
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Input
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
onChange={handleOnChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
id: 'registration.password',
|
|
||||||
defaultMessage: 'Password',
|
|
||||||
})}
|
|
||||||
autoComplete="new-password"
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{AppConfig.isRecaptcha2Enabled() && (
|
|
||||||
<div style={{ width: '330px', padding: '5px 0px 5px 20px' }}>
|
|
||||||
<ReCAPTCHA
|
|
||||||
ref={(el) => setCaptcha(el)}
|
|
||||||
sitekey={AppConfig.getRecaptcha2SiteKey()}
|
|
||||||
onChange={(value: string) => {
|
|
||||||
model.recaptcha = value;
|
|
||||||
setModel(model);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div style={{ fontSize: '12px', padding: '10px 0px' }}>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="registration.termandconditions"
|
id="registration.desc"
|
||||||
defaultMessage="Terms of Client: Please check the WiseMapping Account information you've entered above, and review the Terms of Client here. By clicking on 'Register' below you are agreeing to the Terms of Client above and the Privacy Policy"
|
defaultMessage="Signing up is free and just take a moment "
|
||||||
/>
|
/>
|
||||||
</div>
|
</Typography>
|
||||||
|
<GoogleButton
|
||||||
<SubmitButton
|
text={intl.formatMessage({
|
||||||
value={intl.formatMessage({
|
id: 'registration.google.button',
|
||||||
id: 'registration.register',
|
defaultMessage: 'Sign up with Google',
|
||||||
defaultMessage: 'Register',
|
})}
|
||||||
|
onClick={handleRegisterWithGoogleClick}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item md={2} xs={12}>
|
||||||
|
<Separator
|
||||||
|
responsive={true}
|
||||||
|
maxWidth={maxFormWidth}
|
||||||
|
text={intl.formatMessage({
|
||||||
|
id: 'registration.division',
|
||||||
|
defaultMessage: 'or',
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</form>
|
</Grid>
|
||||||
</FormControl>
|
<Grid item md={5} xs={12}>
|
||||||
</FormContainer>
|
<FormControl css={{ maxWidth: maxFormWidth }}>
|
||||||
|
<form onSubmit={handleOnSubmit}>
|
||||||
|
<GlobalError error={error} />
|
||||||
|
<Input
|
||||||
|
name="email"
|
||||||
|
type="email"
|
||||||
|
onChange={handleOnChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'registration.email',
|
||||||
|
defaultMessage: 'Email',
|
||||||
|
})}
|
||||||
|
autoComplete="email"
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name="firstname"
|
||||||
|
type="text"
|
||||||
|
onChange={handleOnChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'registration.firstname',
|
||||||
|
defaultMessage: 'First Name',
|
||||||
|
})}
|
||||||
|
autoComplete="given-name"
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name="lastname"
|
||||||
|
type="text"
|
||||||
|
onChange={handleOnChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'registration.lastname',
|
||||||
|
defaultMessage: 'Last Name',
|
||||||
|
})}
|
||||||
|
autoComplete="family-name"
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
onChange={handleOnChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'registration.password',
|
||||||
|
defaultMessage: 'Password',
|
||||||
|
})}
|
||||||
|
autoComplete="new-password"
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{AppConfig.isRecaptcha2Enabled() && (
|
||||||
|
<>
|
||||||
|
{/* eslint-disable-next-line react/no-unknown-property */}
|
||||||
|
<div css={recaptchaContainerStyle}>
|
||||||
|
<ReCAPTCHA
|
||||||
|
ref={(el) => setCaptcha(el)}
|
||||||
|
sitekey={AppConfig.getRecaptcha2SiteKey()}
|
||||||
|
onChange={(value: string) => {
|
||||||
|
model.recaptcha = value;
|
||||||
|
setModel(model);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div style={{ fontSize: '12px', padding: '10px 0px' }}>
|
||||||
|
<FormattedMessage
|
||||||
|
id="registration.termandconditions"
|
||||||
|
defaultMessage="Terms of Client: Please check the WiseMapping Account information you've entered above, and review the Terms of Client here. By clicking on 'Register' below you are agreeing to the Terms of Client above and the Privacy Policy"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SubmitButton
|
||||||
|
value={intl.formatMessage({
|
||||||
|
id: 'registration.register',
|
||||||
|
defaultMessage: 'Register',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Link component={RouterLink} to="/c/login">
|
||||||
|
<FormattedMessage id="header.haveaccount" defaultMessage="Already have an account?" />
|
||||||
|
</Link>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
packages/webapp/src/components/registration-page/style.ts
Normal file
10
packages/webapp/src/components/registration-page/style.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
export const recaptchaContainerStyle = css({
|
||||||
|
paddingTop: '10px',
|
||||||
|
// override captcha size, without this the component is not shown horizontally centered
|
||||||
|
'& div div div': {
|
||||||
|
width: '100% !important',
|
||||||
|
height: '100% !important',
|
||||||
|
},
|
||||||
|
});
|
@ -4,6 +4,12 @@ import React from 'react';
|
|||||||
import App from './app';
|
import App from './app';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
newrelic: { noticeError: (Error) => void };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const container = document.getElementById('root') as HTMLElement;
|
const container = document.getElementById('root') as HTMLElement;
|
||||||
const root = createRoot(container!);
|
const root = createRoot(container!);
|
||||||
root.render(<App />);
|
root.render(<App />);
|
||||||
|
@ -51,6 +51,7 @@ const theme = createTheme({
|
|||||||
h4: {
|
h4: {
|
||||||
color: '#ffa800',
|
color: '#ffa800',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
|
marginBottom: '10px',
|
||||||
},
|
},
|
||||||
h6: {
|
h6: {
|
||||||
fontSize: '25px',
|
fontSize: '25px',
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react",
|
|
||||||
"outDir": "./dist/",
|
"outDir": "./dist/",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
@ -10,7 +9,10 @@
|
|||||||
"target": "es6",
|
"target": "es6",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"declaration": true
|
"declaration": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "@emotion/react"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,9 +5,11 @@
|
|||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"module": "es6",
|
"module": "es6",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"jsx": "react",
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "@emotion/react"
|
||||||
|
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user