diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts index f15417ceec..ac77da41ef 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts @@ -5,12 +5,21 @@ import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; import { UmbUserStore } from '../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../core/models'; +import { UmbUserContext } from '../user.context'; +import { UUIButtonState } from '@umbraco-ui/uui'; +import { UmbNotificationDefaultData } from '../../../../core/services/notification/layouts/default'; +import { UmbNotificationService } from '../../../../core/services/notification'; @customElement('umb-editor-action-user-save') export class UmbEditorActionUserSaveElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles, css``]; + @state() + private _saveButtonState?: UUIButtonState; + private _userStore?: UmbUserStore; + private _userContext?: UmbUserContext; + private _notificationService?: UmbNotificationService; connectedCallback(): void { super.connectedCallback(); @@ -18,15 +27,39 @@ export class UmbEditorActionUserSaveElement extends UmbContextConsumerMixin(LitE this.consumeContext('umbUserStore', (userStore: UmbUserStore) => { this._userStore = userStore; }); + + this.consumeContext('umbUserContext', (userContext: UmbUserContext) => { + this._userContext = userContext; + }); + + this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { + this._notificationService = service; + }); } - private _handleSave() { - // this._userStore.save() - console.log('save'); + private async _handleSave() { + // TODO: What if store is not present, what if node is not loaded.... + if (!this._userStore || !this._userContext) return; + + try { + this._saveButtonState = 'waiting'; + const user = this._userContext.getData(); + await this._userStore.save([user]); + const data: UmbNotificationDefaultData = { message: 'User Saved' }; + this._notificationService?.peek('positive', { data }); + this._saveButtonState = 'success'; + } catch (error) { + this._saveButtonState = 'failed'; + } } render() { - return html``; + return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index b4bc135e60..0ad347b83c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -1,17 +1,18 @@ +import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../core/context'; +import { UmbContextProviderMixin, UmbContextConsumerMixin } from '../../../core/context'; import UmbSectionViewUsersElement from '../../sections/users/views/users/section-view-users.element'; import '../../property-editors/content-picker/property-editor-content-picker.element'; import { UmbUserStore } from '../../../core/stores/user/user.store'; import type { UserDetails } from '../../../core/models'; +import { UmbUserContext } from './user.context'; import '../shared/editor-entity-layout/editor-entity-layout.element'; - @customElement('umb-editor-user') -export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { +export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { static styles = [ UUITextStyles, css` @@ -85,22 +86,47 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { @state() private _user?: UserDetails | null; + @state() + private _userName = ''; + @property({ type: String }) entityKey = ''; protected _userStore?: UmbUserStore; protected _usersSubscription?: Subscription; + private _userContext?: UmbUserContext; + + private _userNameSubscription?: Subscription; private _languages = []; //TODO Add languages connectedCallback(): void { super.connectedCallback(); + this.consumeContext('umbUserStore', (usersContext: UmbUserStore) => { this._userStore = usersContext; + this._observeUser(); + }); + } - this._usersSubscription?.unsubscribe(); - this._usersSubscription = this._userStore?.getByKey(this.entityKey).subscribe((user) => { - this._user = user; + private _observeUser() { + this._usersSubscription?.unsubscribe(); + + this._usersSubscription = this._userStore?.getByKey(this.entityKey).subscribe((user) => { + this._user = user; + if (!this._user) return; + + if (!this._userContext) { + this._userContext = new UmbUserContext(this._user); + this.provideContext('umbUserContext', this._userContext); + } else { + this._userContext.update(this._user); + } + + this._userNameSubscription = this._userContext.data.subscribe((user) => { + if (user && user.name !== this._userName) { + this._userName = user.name; + } }); }); } @@ -109,6 +135,7 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { super.disconnectedCallback(); this._usersSubscription?.unsubscribe(); + this._userNameSubscription?.unsubscribe(); } private _updateUserStatus() { @@ -182,8 +209,6 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { private renderRightColumn() { if (!this._user || !this._userStore) return nothing; - console.log('user', this._user); - // const status = this._userStore.getTagLookAndColor(this._user.status); return html`
@@ -242,14 +267,23 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { `; } + // TODO. find a way where we don't have to do this for all editors. + private _handleInput(event: UUIInputEvent) { + if (event instanceof UUIInputEvent) { + const target = event.composedPath()[0] as UUIInputElement; + + if (typeof target?.value === 'string') { + this._userContext?.update({ name: target.value }); + } + } + } + render() { if (!this._user) return html`User not found`; return html` - - + +
${this.renderLeftColumn()}
${this.renderRightColumn()}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts new file mode 100644 index 0000000000..8d11cc64e3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts @@ -0,0 +1,36 @@ +import { BehaviorSubject, Observable } from 'rxjs'; +import type { UserDetails } from '../../../core/models'; + +export class UmbUserContext { + // TODO: figure out how fine grained we want to make our observables. + private _data = new BehaviorSubject({ + key: '', + name: '', + icon: '', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + email: '', + language: '', + status: '', + updateDate: '8/27/2022', + createDate: '9/19/2022', + failedLoginAttempts: 0, + }); + public readonly data: Observable = this._data.asObservable(); + + constructor(user: UserDetails) { + if (!user) return; + this._data.next(user); + } + + // TODO: figure out how we want to update data + public update(data: Partial) { + this._data.next({ ...this._data.getValue(), ...data }); + } + + public getData() { + return this._data.getValue(); + } +}