Simple page de modification de profil
This commit is contained in:
parent
05dd505d6b
commit
758c166f27
|
@ -3,6 +3,7 @@ import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom";
|
||||||
import { HomePage } from './HomePage/HomePage';
|
import { HomePage } from './HomePage/HomePage';
|
||||||
import { store } from '../store/store';
|
import { store } from '../store/store';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { ProfilePage } from './ProfilePage/ProfilePage';
|
||||||
|
|
||||||
export class App extends React.Component {
|
export class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
@ -11,6 +12,7 @@ export class App extends React.Component {
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/" exact component={HomePage} />
|
<Route path="/" exact component={HomePage} />
|
||||||
|
<Route path="/profile" exact component={ProfilePage} />
|
||||||
<Route component={() => <Redirect to="/" />} />
|
<Route component={() => <Redirect to="/" />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|
|
@ -7,7 +7,7 @@ export function HomePage() {
|
||||||
const currentUser = useSelector((state: RootState) => state.auth.currentUser);
|
const currentUser = useSelector((state: RootState) => state.auth.currentUser);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title="Daddy - Accueil">
|
<Page title="Accueil">
|
||||||
<div className="container is-fluid">
|
<div className="container is-fluid">
|
||||||
<section className="section">
|
<section className="section">
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
|
@ -15,7 +15,7 @@ export function HomePage() {
|
||||||
<div className="box">
|
<div className="box">
|
||||||
{
|
{
|
||||||
currentUser && currentUser.email ?
|
currentUser && currentUser.email ?
|
||||||
<p>Bonjour <span className="has-text-weight-bold">{currentUser.email}</span> !</p> :
|
<p>Bonjour <span className="has-text-weight-bold">{currentUser.name ? currentUser.name : currentUser.email}</span> !</p> :
|
||||||
<p>Veuillez vous authentifier.</p>
|
<p>Veuillez vous authentifier.</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,44 +1,62 @@
|
||||||
import React from 'react';
|
import React, { Fragment, useState } from 'react';
|
||||||
import logo from '../resources/logo.svg';
|
import logo from '../resources/logo.svg';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { RootState } from '../store/reducers/root';
|
import { RootState } from '../store/reducers/root';
|
||||||
import { Config } from '../config';
|
import { Config } from '../config';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
export function Navbar() {
|
export function Navbar() {
|
||||||
const isAuthenticated = useSelector<RootState>(state => state.auth.isAuthenticated);
|
const isAuthenticated = useSelector<RootState>(state => state.auth.isAuthenticated);
|
||||||
|
|
||||||
|
const [ isActive, setActive ] = useState(false);
|
||||||
|
|
||||||
|
const toggleMenu = () => {
|
||||||
|
setActive(active => !active);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="navbar" role="navigation" aria-label="main navigation">
|
<nav className="navbar" role="navigation" aria-label="main navigation">
|
||||||
<div className="container is-fluid">
|
<div className="container is-fluid">
|
||||||
<div className="navbar-brand">
|
<div className="navbar-brand">
|
||||||
<a className="navbar-item" href="#/">
|
<Link className="navbar-item" to="/">
|
||||||
<img src={logo} style={{marginRight:'5px',width:'28px',height:'28px'}} />
|
<img src={logo} style={{marginRight:'5px',width:'28px',height:'28px'}} />
|
||||||
<h1 className="is-size-4">Daddy</h1>
|
<h1 className="is-size-4">Daddy</h1>
|
||||||
</a>
|
</Link>
|
||||||
<a role="button" className="navbar-burger" aria-label="menu" aria-expanded="false">
|
<a role="button"
|
||||||
|
className={`navbar-burger ${isActive ? 'is-active' : ''}`}
|
||||||
|
onClick={toggleMenu}
|
||||||
|
aria-label="menu"
|
||||||
|
aria-expanded="false">
|
||||||
<span aria-hidden="true"></span>
|
<span aria-hidden="true"></span>
|
||||||
<span aria-hidden="true"></span>
|
<span aria-hidden="true"></span>
|
||||||
<span aria-hidden="true"></span>
|
<span aria-hidden="true"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="navbar-menu">
|
<div className={`navbar-menu ${isActive ? 'is-active' : ''}`}>
|
||||||
<div className="navbar-end">
|
<div className="navbar-end">
|
||||||
<div className="navbar-item">
|
<div className="navbar-item">
|
||||||
|
<div className="buttons">
|
||||||
{
|
{
|
||||||
isAuthenticated ?
|
isAuthenticated ?
|
||||||
<a className="button is-small" href={Config.logoutURL}>
|
<Fragment>
|
||||||
<span className="icon">
|
<Link to="/profile" className="button">
|
||||||
<i className="fas fa-sign-out-alt"></i>
|
<span className="icon">
|
||||||
</span>
|
<i className="fas fa-user"></i>
|
||||||
<span>Se déconnecter</span>
|
</span>
|
||||||
</a> :
|
</Link>
|
||||||
<a className="button is-small" href={Config.loginURL}>
|
<a className="button" href={Config.logoutURL}>
|
||||||
|
<span className="icon">
|
||||||
|
<i className="fas fa-sign-out-alt"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</Fragment> :
|
||||||
|
<a className="button" href={Config.loginURL}>
|
||||||
<span className="icon">
|
<span className="icon">
|
||||||
<i className="fas fa-sign-in-alt"></i>
|
<i className="fas fa-sign-in-alt"></i>
|
||||||
</span>
|
</span>
|
||||||
<span>Se connecter</span>
|
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,6 +25,6 @@ export class Page extends React.PureComponent<PageProps> {
|
||||||
|
|
||||||
updateTitle() {
|
updateTitle() {
|
||||||
const { title } = this.props;
|
const { title } = this.props;
|
||||||
if (title !== undefined) window.document.title = title;
|
if (title !== undefined) window.document.title = title + ' - Daddy';
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { Page } from '../Page';
|
||||||
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
import { RootState } from '../../store/reducers/root';
|
||||||
|
import { UserForm } from '../UserForm';
|
||||||
|
import { Loader } from '../Loader';
|
||||||
|
import { User } from '../../types/user';
|
||||||
|
import { updateProfile } from '../../store/actions/profile';
|
||||||
|
|
||||||
|
export function ProfilePage() {
|
||||||
|
const currentUser = useSelector((state: RootState) => state.auth.currentUser);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const onUserChange = (user: User) => {
|
||||||
|
if (currentUser.name !== user.name) {
|
||||||
|
dispatch(updateProfile({ name: user.name }))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page title="Mon profil">
|
||||||
|
<div className="container is-fluid">
|
||||||
|
<section className="section">
|
||||||
|
<div className="columns">
|
||||||
|
<div className="column is-6 is-offset-3">
|
||||||
|
<h2 className="is-size-2 subtitle">Mon profil</h2>
|
||||||
|
{
|
||||||
|
currentUser ?
|
||||||
|
<UserForm onChange={onUserChange} user={currentUser} /> :
|
||||||
|
<Loader />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
import React, { useState, ChangeEvent, useEffect } from 'react';
|
||||||
|
import { User } from '../types/user';
|
||||||
|
|
||||||
|
export interface UserFormProps {
|
||||||
|
user: User
|
||||||
|
onChange?: (user: User) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserForm({ user, onChange }: UserFormProps) {
|
||||||
|
const [ state, setState ] = useState({
|
||||||
|
changed: false,
|
||||||
|
user: {
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
createdAt: null,
|
||||||
|
connectedAt: null,
|
||||||
|
...user,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSaveClick = () => {
|
||||||
|
if (!state.changed) return;
|
||||||
|
if (typeof onChange !== 'function') return;
|
||||||
|
onChange(state.user);
|
||||||
|
setState(state => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
changed: false,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUserAttrChange = function(attrName: string, evt: ChangeEvent<HTMLInputElement>) {
|
||||||
|
const value = evt.currentTarget.value;
|
||||||
|
setState(state => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
changed: true,
|
||||||
|
user: {
|
||||||
|
...state.user,
|
||||||
|
[attrName]: value,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="form">
|
||||||
|
<div className="field">
|
||||||
|
<label className="label">Nom d'utilisateur</label>
|
||||||
|
<div className="control">
|
||||||
|
<input type="text" className="input" value={state.user.name}
|
||||||
|
onChange={onUserAttrChange.bind(null, "name")} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="field">
|
||||||
|
<label className="label">Adresse courriel</label>
|
||||||
|
<div className="control">
|
||||||
|
<p className="input is-static">{state.user.email}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="field">
|
||||||
|
<label className="label">Date de dernière connexion</label>
|
||||||
|
<div className="control">
|
||||||
|
<p className="input is-static">{state.user.connectedAt}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="field">
|
||||||
|
<label className="label">Date de création</label>
|
||||||
|
<div className="control">
|
||||||
|
<p className="input is-static">{state.user.createdAt}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="buttons is-right">
|
||||||
|
<button disabled={!state.changed}
|
||||||
|
className="button is-primary" onClick={onSaveClick}>Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -16,4 +16,25 @@ export interface fetchProfileSuccessAction extends Action {
|
||||||
|
|
||||||
export function fetchProfile(): fetchProfileRequestAction {
|
export function fetchProfile(): fetchProfileRequestAction {
|
||||||
return { type: FETCH_PROFILE_REQUEST }
|
return { type: FETCH_PROFILE_REQUEST }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UPDATE_PROFILE_REQUEST = 'UPDATE_PROFILE_REQUEST';
|
||||||
|
export const UPDATE_PROFILE_SUCCESS = 'UPDATE_PROFILE_SUCCESS';
|
||||||
|
export const UPDATE_PROFILE_FAILURE = 'UPDATE_PROFILE_FAILURE';
|
||||||
|
|
||||||
|
export interface ProfileChanges {
|
||||||
|
name?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface updateProfileRequestAction extends Action {
|
||||||
|
changes: ProfileChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface updateProfileSuccessAction extends Action {
|
||||||
|
profile: User
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function updateProfile(changes: ProfileChanges): updateProfileRequestAction {
|
||||||
|
return { type: UPDATE_PROFILE_REQUEST, changes }
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { Action } from "redux";
|
import { Action } from "redux";
|
||||||
import { User } from "../../types/user";
|
import { User } from "../../types/user";
|
||||||
import { SET_CURRENT_USER, setCurrentUserAction } from "../actions/auth";
|
import { SET_CURRENT_USER, setCurrentUserAction } from "../actions/auth";
|
||||||
import { FETCH_PROFILE_SUCCESS, fetchProfileSuccessAction } from "../actions/profile";
|
import { FETCH_PROFILE_SUCCESS, fetchProfileSuccessAction, updateProfileSuccessAction, UPDATE_PROFILE_SUCCESS, updateProfileRequestAction } from "../actions/profile";
|
||||||
|
|
||||||
export interface AuthState {
|
export interface AuthState {
|
||||||
isAuthenticated: boolean
|
isAuthenticated: boolean
|
||||||
|
@ -19,6 +19,8 @@ export function authReducer(state = defaultState, action: Action): AuthState {
|
||||||
return handleSetCurrentUser(state, action as setCurrentUserAction);
|
return handleSetCurrentUser(state, action as setCurrentUserAction);
|
||||||
case FETCH_PROFILE_SUCCESS:
|
case FETCH_PROFILE_SUCCESS:
|
||||||
return handleFetchProfileSuccess(state, action as fetchProfileSuccessAction);
|
return handleFetchProfileSuccess(state, action as fetchProfileSuccessAction);
|
||||||
|
case UPDATE_PROFILE_SUCCESS:
|
||||||
|
return handleFetchProfileSuccess(state, action as updateProfileSuccessAction);
|
||||||
|
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
|
@ -39,9 +41,17 @@ function handleFetchProfileSuccess(state: AuthState, { profile }: fetchProfileSu
|
||||||
...state,
|
...state,
|
||||||
isAuthenticated: true,
|
isAuthenticated: true,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
email: profile.email,
|
...profile,
|
||||||
connectedAt: profile.connectedAt,
|
}
|
||||||
createdAt: profile.createdAt,
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleUpdateProfileSuccess(state: AuthState, { profile }: updateProfileSuccessAction): AuthState {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isAuthenticated: true,
|
||||||
|
currentUser: {
|
||||||
|
...profile,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
|
@ -1,15 +1,15 @@
|
||||||
import { DaddyClient, getClient } from "../../util/daddy";
|
import { DaddyClient, getClient } from "../../util/daddy";
|
||||||
import { Config } from "../../config";
|
import { Config } from "../../config";
|
||||||
import { all, takeLatest, put, select } from "redux-saga/effects";
|
import { all, takeLatest, put, select } from "redux-saga/effects";
|
||||||
import { FETCH_PROFILE_REQUEST, fetchProfile, FETCH_PROFILE_FAILURE, FETCH_PROFILE_SUCCESS } from "../actions/profile";
|
import { FETCH_PROFILE_REQUEST, fetchProfile, FETCH_PROFILE_FAILURE, FETCH_PROFILE_SUCCESS, updateProfileRequestAction, UPDATE_PROFILE_REQUEST, UPDATE_PROFILE_FAILURE, UPDATE_PROFILE_SUCCESS } from "../actions/profile";
|
||||||
import { SET_CURRENT_USER } from "../actions/auth";
|
import { SET_CURRENT_USER } from "../actions/auth";
|
||||||
import { RootState } from "../reducers/root";
|
|
||||||
import { User } from "../../types/user";
|
import { User } from "../../types/user";
|
||||||
|
|
||||||
export function* usersRootSaga() {
|
export function* profileRootSaga() {
|
||||||
yield all([
|
yield all([
|
||||||
takeLatest(SET_CURRENT_USER, onCurrentUserChangeSaga),
|
takeLatest(SET_CURRENT_USER, onCurrentUserChangeSaga),
|
||||||
takeLatest(FETCH_PROFILE_REQUEST, fetchProfileSaga),
|
takeLatest(FETCH_PROFILE_REQUEST, fetchProfileSaga),
|
||||||
|
takeLatest(UPDATE_PROFILE_REQUEST, updateProfileSaga),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +23,24 @@ export function* fetchProfileSaga() {
|
||||||
let profile: User;
|
let profile: User;
|
||||||
try {
|
try {
|
||||||
profile = yield client.fetchProfile().then(result => result.userProfile);
|
profile = yield client.fetchProfile().then(result => result.userProfile);
|
||||||
console.log(profile);
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
yield put({ type: FETCH_PROFILE_FAILURE, err });
|
yield put({ type: FETCH_PROFILE_FAILURE, err });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put({type: FETCH_PROFILE_SUCCESS, profile });
|
yield put({type: FETCH_PROFILE_SUCCESS, profile });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* updateProfileSaga({ changes }: updateProfileRequestAction) {
|
||||||
|
const client = getClient(Config.graphQLEndpoint, Config.subscriptionEndpoint);
|
||||||
|
|
||||||
|
let profile: User;
|
||||||
|
try {
|
||||||
|
profile = yield client.updateProfile(changes).then(result => result.updateProfile);
|
||||||
|
} catch(err) {
|
||||||
|
yield put({ type: UPDATE_PROFILE_FAILURE, err });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put({type: UPDATE_PROFILE_SUCCESS, profile });
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
import { all } from 'redux-saga/effects';
|
import { all } from 'redux-saga/effects';
|
||||||
import { failureRootSaga } from './failure';
|
import { failureRootSaga } from './failure';
|
||||||
import { initRootSaga } from './init';
|
import { initRootSaga } from './init';
|
||||||
import { usersRootSaga } from './users';
|
import { profileRootSaga } from './profile';
|
||||||
|
|
||||||
export function* rootSaga() {
|
export function* rootSaga() {
|
||||||
yield all([
|
yield all([
|
||||||
initRootSaga(),
|
initRootSaga(),
|
||||||
failureRootSaga(),
|
failureRootSaga(),
|
||||||
usersRootSaga(),
|
profileRootSaga(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export interface User {
|
export interface User {
|
||||||
email: string
|
email: string
|
||||||
|
name?: string
|
||||||
connectedAt?: Date
|
connectedAt?: Date
|
||||||
createdAt?: Date
|
createdAt?: Date
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
import ApolloClient from 'apollo-client';
|
import ApolloClient, { DefaultOptions } from 'apollo-client';
|
||||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||||
import { split } from 'apollo-link';
|
import { split } from 'apollo-link';
|
||||||
import { HttpLink } from 'apollo-link-http';
|
import { HttpLink } from 'apollo-link-http';
|
||||||
import { WebSocketLink } from 'apollo-link-ws';
|
import { WebSocketLink } from 'apollo-link-ws';
|
||||||
import { getMainDefinition } from 'apollo-utilities';
|
import { getMainDefinition, variablesInOperation } from 'apollo-utilities';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
|
import { ProfileChanges } from '../store/actions/profile';
|
||||||
|
|
||||||
export class UnauthorizedError extends Error {
|
export class UnauthorizedError extends Error {
|
||||||
constructor(...args: any[]) {
|
constructor(...args: any[]) {
|
||||||
|
@ -54,10 +55,22 @@ export class DaddyClient {
|
||||||
wsLink,
|
wsLink,
|
||||||
httpLink,
|
httpLink,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const defaultOptions: DefaultOptions = {
|
||||||
|
watchQuery: {
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
errorPolicy: 'ignore',
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
errorPolicy: 'all',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
this.gql = new ApolloClient<any>({
|
this.gql = new ApolloClient<any>({
|
||||||
link: link,
|
link: link,
|
||||||
cache: new InMemoryCache(),
|
cache: new InMemoryCache(),
|
||||||
|
defaultOptions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +79,7 @@ export class DaddyClient {
|
||||||
query: gql`
|
query: gql`
|
||||||
query {
|
query {
|
||||||
userProfile {
|
userProfile {
|
||||||
|
name,
|
||||||
email,
|
email,
|
||||||
createdAt,
|
createdAt,
|
||||||
connectedAt
|
connectedAt
|
||||||
|
@ -75,6 +89,24 @@ export class DaddyClient {
|
||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateProfile(changes: ProfileChanges) {
|
||||||
|
return this.gql.mutate({
|
||||||
|
variables: {
|
||||||
|
changes,
|
||||||
|
},
|
||||||
|
mutation: gql`
|
||||||
|
mutation updateProfile($changes: ProfileChanges!) {
|
||||||
|
updateProfile(changes: $changes) {
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
createdAt,
|
||||||
|
connectedAt
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
})
|
||||||
|
.then(this.assertAuthorization)
|
||||||
|
}
|
||||||
|
|
||||||
assertAuthorization({ status, data }: any) {
|
assertAuthorization({ status, data }: any) {
|
||||||
if (status === 401) return Promise.reject(new UnauthorizedError());
|
if (status === 401) return Promise.reject(new UnauthorizedError());
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -31,5 +31,28 @@ func handleUserProfile(ctx context.Context) (*model.User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUpdateUserProfile(ctx context.Context, changes model.ProfileChanges) (*model.User, error) {
|
func handleUpdateUserProfile(ctx context.Context, changes model.ProfileChanges) (*model.User, error) {
|
||||||
return nil, nil
|
db, err := getDB(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userEmail, err := session.UserEmail(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repo := model.NewUserRepository(db)
|
||||||
|
|
||||||
|
userChanges := &model.User{}
|
||||||
|
|
||||||
|
if changes.Name != nil {
|
||||||
|
userChanges.Name = changes.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := repo.UpdateUserByEmail(ctx, userEmail, userChanges)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,23 @@ func (r *UserRepository) FindUserByEmail(ctx context.Context, email string) (*Us
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UserRepository) UpdateUserByEmail(ctx context.Context, email string, changes *User) (*User, error) {
|
||||||
|
user := &User{
|
||||||
|
Email: email,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.db.First(user, "email = ?", email).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not find user")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.db.Model(user).Updates(changes).Error; err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not update user")
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewUserRepository(db *gorm.DB) *UserRepository {
|
func NewUserRepository(db *gorm.DB) *UserRepository {
|
||||||
return &UserRepository{db}
|
return &UserRepository{db}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue