mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-01 12:24:28 +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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
/**
|
||||
@ -63,20 +77,6 @@ Application.Controllers.controller('DashboardController', ['$scope', 'memberProm
|
||||
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
|
||||
return initialize();
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco
|
||||
$scope.method = 'patch';
|
||||
|
||||
// Current user's profile
|
||||
$scope.user = memberPromise;
|
||||
$scope.user = cleanUser(memberPromise);
|
||||
|
||||
// default : do not show the group changing form
|
||||
$scope.group =
|
||||
@ -293,6 +293,13 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco
|
||||
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
|
||||
return initialize();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Plan } from './plan';
|
||||
import { TDateISO } from '../typings/date-iso';
|
||||
|
||||
export enum UserRole {
|
||||
Member = 'member',
|
||||
@ -63,13 +64,13 @@ export interface User {
|
||||
statistic_profile: {
|
||||
id: number,
|
||||
gender: string,
|
||||
birthday: Date
|
||||
birthday: TDateISO
|
||||
},
|
||||
subscribed_plan: Plan,
|
||||
subscription: {
|
||||
id: number,
|
||||
expired_at: Date,
|
||||
canceled_at: Date,
|
||||
expired_at: TDateISO,
|
||||
canceled_at: TDateISO,
|
||||
stripe: boolean,
|
||||
plan: {
|
||||
id: number,
|
||||
@ -82,5 +83,5 @@ export interface User {
|
||||
},
|
||||
training_credits: Array<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 class="panel panel-default bg-light m">
|
||||
<div class="panel-body m-r">
|
||||
<user-profile-form user="user" action="'update'" />
|
||||
<ng-include src="'/shared/_member_form.html'"></ng-include>
|
||||
</div> <!-- ./panel-body -->
|
||||
</section>
|
||||
|
Loading…
Reference in New Issue
Block a user