---
description: >-
  The following is a walkthrough of creating the Update User Account function
  example
---

# Update User Account callable function example

* [Example change request](#example-change-request)
  * [Overview](#overview)
  * [Acceptance criteria](#acceptance-criteria)
  * [Technical requirements](#technical-requirements)
* [Type of function](#type-of-function)
* [Create onUpdateAccount function](#create-onupdateaccount-function)
* [Build the functions](#build-the-functions)
* [Deploy functions](#deploy-functions)
* [Update the frontend application for new API interaction](#update-the-frontend-application-for-new-api-interaction)
  * [Update Account state management](#update-account-state-management)
    * [Update actions](#update-actions)
    * [Update reducer](#update-reducer)
    * [Update facade](#update-facade)
    * [Update effects](#update-effects)
  * [Update AccountService](#update-accountservice)
  * [Update AccountModule for forms integration](#update-accountmodule-for-forms-integration)
  * [Update AccountComponent class](#update-accountcomponent-class)
  * [Update AccountComponent template](#update-accountcomponent-template)
* [Further improvements](#further-improvements)

## Example change request

#### Overview

Users need to be able to update their accounts with a Github URL.

#### Acceptance criteria

* `Login` as any user
* `Navigate` to the user account view
  * `/account`
* `Observe` view includes the following:
  * Update Github URL: \<input>
  * Button to update the user's Github URL



#### Technical requirements

* `Account` template updates to include new design
* `Account` component update to interact with the state
* `Account` state management updated to interact with API
* `onUpdateAccount` HTTPS callable function to update the `/users/{{uid}}` document with new Github URL property



## Type of function

For this update, we will be creating an [HTTPS callable function](https://firebase.google.com/docs/functions/callable) that allows users to update their account information directly from the application.

Additional types of functions can be reviewed here: [Cloud Functions](https://firebase.google.com/docs/functions)

## Create onUpdateAccount function

In the `apps\full-stack-typescript-api\src\functions` folder, create the following:

```
functions
  - account
    - index.ts
```

`Update` `apps\full-stack-typescript-api\src\functions\account\index.ts` to be:

```typescript
import { User } from '@full-stack-typescript/models';
import * as admin from 'firebase-admin';

const {
    firestoreInstance,
// eslint-disable-next-line @typescript-eslint/no-var-requires
} = require('../../utils/admin');

export async function onUpdateAccount(data: User, context) {

    const batch = firestoreInstance.batch(); // Get a new write batch
    const serverTimestamp = admin.firestore.Timestamp.now();
    const uid = context.auth.uid;

    const userDoc = firestoreInstance.collection('users').doc(uid); // Get paths

    batch.update(userDoc, {
        ...data,
        updatedAt: serverTimestamp
    }, { merge: true });

    return batch.commit();

};

```

The new function receives a `data` payload of type `User` and merges the new data to the users document in our database.

`Update` `apps\full-stack-typescript-api\src\main.ts` to include the new function.

```typescript
import * as authFunctions from './functions/auth';

...

// Account
export const onUpdateAccount = functions.https.onCall((data, context) => {
    return accountFunctions.onUpdateAccount(data, context);
});
```

The `main.ts` file is our primary entry point for our functions and needs to be updated so that our new function is included when the project is built.

## Build the functions

Run the following command to build the functions application:

`nx build full-stack-typescript-api`

## Deploy functions

Run the following command to deploy new and updated functions:

`firebase deploy --only functions`

## Update the frontend application for new API interaction

Now that we've created a secure method for interacting with the database, we need to update the frontend application to integrate with the new function.

### Update Account state management

#### Update actions

`Update` `libs\features\account\src\lib\+state\account.actions.ts` to include the new actions:

* updateAccount
* updateAccountFailure
* updateAccountSuccess

```typescript
...
export const updateAccount = createAction(
  '[Account] Update account',
  props<{ account: User }>()
);

export const updateAccountFailure = createAction(
  '[Account] Update account Failure',
  props<{ error: any }>()
);

export const updateAccountSuccess = createAction(
  '[Account] Update account Success'
);
```

#### Update reducer

`Update` `libs\features\account\src\lib\+state\account.reducer.ts` to include:

```typescript
const accountReducer = createReducer(
    initialState,
    ...
    on(accountActions.loadAccountFailure, accountActions.updateAccountFailure, (state, { error }) => ({
        ...state,
        error,
        isLoaded: false,
        isLoading: false
    })),
    ...
    on(accountActions.updateAccount, (state) => ({
        ...state,
        isLoading: true
    })),
    on(accountActions.updateAccountSuccess, (state) => ({
        ...state,
        error: null,
        isLoaded: false
    }))
);
```

#### Update facade

`Update` `libs\features\account\src\lib\+state\account.facade.ts` to include:

```typescript
    updateAccount(account: User) {
        this.store.dispatch(updateAccount({ account }));
    }
```

#### Update effects

`Update` `libs\features\account\src\lib\+state\account.effects.ts` to include:

```typescript
	updateAccount$ = createEffect(() =>
		this.actions$.pipe(
			ofType(accountActions.updateAccount),
			exhaustMap(({ account }) =>
				this.accountService.updateAccount(account).pipe(
					map(() => {
						return accountActions.updateAccountSuccess();
					}),
					catchError((error) => of(accountActions.updateAccountFailure({ error })))
				)
			)
		)
	);
```

### Update AccountService

`Update` `libs\services\account\src\lib\account.service.ts` to include:

```typescript
import { AngularFireFunctions } from '@angular/fire/compat/functions';

	constructor(private fns: AngularFireFunctions, afs: AngularFirestore) {

		super(afs);

	}
	
	updateAccount(account: User): Observable<User> {

		const callable = this.fns.httpsCallable('onUpdateAccount');
		return callable(account) as Observable<User>;

	}
```

### Update AccountModule for forms integration

`Update` `libs\features\account\src\lib\account.module.ts` to include the `FormsModule` :

```typescript
import { FormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ...
    FormsModule,
    ...
  ],
})
export class AccountModule {}
```

### Update AccountComponent class

`Update` `libs\features\account\src\lib\account.component.ts` to include:

```typescript
	githubURL = '';
	
	onUpdateAccount() {

		this.accountFacade.updateAccount({ githubURL: this.githubURL });

	}
```

### Update AccountComponent template

`Update` `libs\features\account\src\lib\account.component.html` to include:

```html
<div>
    Update Github URL: <input type="text" [(ngModel)]="githubURL">
    <button (click)="onUpdateAccount()">Update Account</button>
</div>
```

## Further improvements

There is now a secure way for users to update their account information with the database. The `onUpdateAccount` function and `Account` state accepts a `User` payload which can include all of the attributes of `User`.&#x20;

The `AccountComponent` can be improved to enable updating of all `User` properties.
