mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-10 21:24:20 +01:00
(wip)(ui) user edition form
This commit is contained in:
parent
6ec6a8c4c9
commit
0d09ddd2fa
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface ErrorBoundaryState {
|
||||||
|
hasError: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component will catch javascript errors anywhere in their child component tree and display a message to the user.
|
||||||
|
* @see https://reactjs.org/docs/error-boundaries.html
|
||||||
|
*/
|
||||||
|
export class ErrorBoundary extends React.Component<unknown, ErrorBoundaryState> {
|
||||||
|
constructor (props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { hasError: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromError () {
|
||||||
|
return { hasError: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch (error, errorInfo) {
|
||||||
|
console.error(error, errorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
return <h1>Something went wrong.</h1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { react2angular } from 'react2angular';
|
||||||
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||||
|
import { User } from '../../models/user';
|
||||||
|
import { IApplication } from '../../models/application';
|
||||||
|
import { Loader } from '../base/loader';
|
||||||
|
import { FormInput } from '../form/form-input';
|
||||||
|
|
||||||
|
declare const Application: IApplication;
|
||||||
|
|
||||||
|
interface UserProfileFormProps {
|
||||||
|
action: 'create' | 'update',
|
||||||
|
user: User;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, user, className }) => {
|
||||||
|
const { handleSubmit, register } = useForm<User>({ defaultValues: { ...user } });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback triggered when the form is submitted: process with the user creation or update.
|
||||||
|
*/
|
||||||
|
const onSubmit: SubmitHandler<User> = (data: User) => {
|
||||||
|
console.log(action, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className={`user-profile-form ${className}`} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<FormInput id="email" register={register} rules={{ required: true }} label="email" />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UserProfileFormWrapper: React.FC<UserProfileFormProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<Loader>
|
||||||
|
<UserProfileForm {...props} />
|
||||||
|
</Loader>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Application.Components.component('userProfileForm', react2angular(UserProfileFormWrapper, ['action', 'user', 'className']));
|
@ -41,6 +41,20 @@ Application.Controllers.controller('DashboardController', ['$scope', 'memberProm
|
|||||||
return trainingsPromise.find(t => t.id === trainingId).name;
|
return trainingsPromise.find(t => t.id === trainingId).name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used in PaymentScheduleDashboard, in case of error
|
||||||
|
*/
|
||||||
|
$scope.onError = function (message) {
|
||||||
|
growl.error(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback triggered when the user has successfully updated his card
|
||||||
|
*/
|
||||||
|
$scope.onCardUpdateSuccess = function (message) {
|
||||||
|
growl.success(message);
|
||||||
|
};
|
||||||
|
|
||||||
/* PRIVATE SCOPE */
|
/* PRIVATE SCOPE */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,20 +77,6 @@ Application.Controllers.controller('DashboardController', ['$scope', 'memberProm
|
|||||||
return networks;
|
return networks;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback used in PaymentScheduleDashboard, in case of error
|
|
||||||
*/
|
|
||||||
$scope.onError = function (message) {
|
|
||||||
growl.error(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback triggered when the user has successfully updated his card
|
|
||||||
*/
|
|
||||||
$scope.onCardUpdateSuccess = function (message) {
|
|
||||||
growl.success(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
// !!! MUST BE CALLED AT THE END of the controller
|
// !!! MUST BE CALLED AT THE END of the controller
|
||||||
return initialize();
|
return initialize();
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco
|
|||||||
$scope.method = 'patch';
|
$scope.method = 'patch';
|
||||||
|
|
||||||
// Current user's profile
|
// Current user's profile
|
||||||
$scope.user = memberPromise;
|
$scope.user = cleanUser(memberPromise);
|
||||||
|
|
||||||
// default : do not show the group changing form
|
// default : do not show the group changing form
|
||||||
$scope.group =
|
$scope.group =
|
||||||
@ -293,6 +293,13 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco
|
|||||||
return angular.forEach(activeProviderPromise.mapping, map => $scope.preventField[map] = true);
|
return angular.forEach(activeProviderPromise.mapping, map => $scope.preventField[map] = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// prepare the user for the react-hook-form
|
||||||
|
function cleanUser (user) {
|
||||||
|
delete user.$promise;
|
||||||
|
delete user.$resolved;
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
// !!! MUST BE CALLED AT THE END of the controller
|
// !!! MUST BE CALLED AT THE END of the controller
|
||||||
return initialize();
|
return initialize();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Plan } from './plan';
|
import { Plan } from './plan';
|
||||||
|
import { TDateISO } from '../typings/date-iso';
|
||||||
|
|
||||||
export enum UserRole {
|
export enum UserRole {
|
||||||
Member = 'member',
|
Member = 'member',
|
||||||
@ -63,13 +64,13 @@ export interface User {
|
|||||||
statistic_profile: {
|
statistic_profile: {
|
||||||
id: number,
|
id: number,
|
||||||
gender: string,
|
gender: string,
|
||||||
birthday: Date
|
birthday: TDateISO
|
||||||
},
|
},
|
||||||
subscribed_plan: Plan,
|
subscribed_plan: Plan,
|
||||||
subscription: {
|
subscription: {
|
||||||
id: number,
|
id: number,
|
||||||
expired_at: Date,
|
expired_at: TDateISO,
|
||||||
canceled_at: Date,
|
canceled_at: TDateISO,
|
||||||
stripe: boolean,
|
stripe: boolean,
|
||||||
plan: {
|
plan: {
|
||||||
id: number,
|
id: number,
|
||||||
@ -82,5 +83,5 @@ export interface User {
|
|||||||
},
|
},
|
||||||
training_credits: Array<number>,
|
training_credits: Array<number>,
|
||||||
machine_credits: Array<{machine_id: number, hours_used: number}>,
|
machine_credits: Array<{machine_id: number, hours_used: number}>,
|
||||||
last_sign_in_at: Date
|
last_sign_in_at: TDateISO
|
||||||
}
|
}
|
||||||
|
28
app/frontend/src/javascript/typings/date-iso.d.ts
vendored
Normal file
28
app/frontend/src/javascript/typings/date-iso.d.ts
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// from https://gist.github.com/MrChocolatine/367fb2a35d02f6175cc8ccb3d3a20054
|
||||||
|
|
||||||
|
type TYear = `${number}${number}${number}${number}`;
|
||||||
|
type TMonth = `${number}${number}`;
|
||||||
|
type TDay = `${number}${number}`;
|
||||||
|
type THours = `${number}${number}`;
|
||||||
|
type TMinutes = `${number}${number}`;
|
||||||
|
type TSeconds = `${number}${number}`;
|
||||||
|
type TMilliseconds = `${number}${number}${number}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a string like `2021-01-08`
|
||||||
|
*/
|
||||||
|
type TDateISODate = `${TYear}-${TMonth}-${TDay}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a string like `14:42:34.678`
|
||||||
|
*/
|
||||||
|
type TDateISOTime = `${THours}:${TMinutes}:${TSeconds}.${TMilliseconds}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a string like `2021-01-08T14:42:34.678Z` (format: ISO 8601).
|
||||||
|
*
|
||||||
|
* It is not possible to type more precisely (list every possible values for months, hours etc) as
|
||||||
|
* it would result in a warning from TypeScript:
|
||||||
|
* "Expression produces a union type that is too complex to represent. ts(2590)
|
||||||
|
*/
|
||||||
|
export type TDateISO = `${TDateISODate}T${TDateISOTime}Z`;
|
@ -121,6 +121,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="panel panel-default bg-light m">
|
<section class="panel panel-default bg-light m">
|
||||||
<div class="panel-body m-r">
|
<div class="panel-body m-r">
|
||||||
|
<user-profile-form user="user" action="'update'" />
|
||||||
<ng-include src="'/shared/_member_form.html'"></ng-include>
|
<ng-include src="'/shared/_member_form.html'"></ng-include>
|
||||||
</div> <!-- ./panel-body -->
|
</div> <!-- ./panel-body -->
|
||||||
</section>
|
</section>
|
||||||
|
Loading…
Reference in New Issue
Block a user