1
0
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:
Sylvain 2022-04-25 17:23:50 +02:00
parent 6ec6a8c4c9
commit 0d09ddd2fa
7 changed files with 130 additions and 19 deletions

View File

@ -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;
}
}

View File

@ -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']));

View File

@ -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();
} }

View File

@ -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();
} }

View File

@ -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
} }

View 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`;

View File

@ -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>