-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support custom fields in user-profile-widget + Edit/Delete flows (
#843) ## Related Issues fixes descope/etc#8220 Part of descope/etc#6501 ## Description Widget Profile widget to support custom fields presentation - created a new mixin to support custom fields userAttribute component. ![image](https://github.com/user-attachments/assets/6a6fed3b-6587-4160-aaaa-d466dabaa7c7) --------- Signed-off-by: Nitzan Peretz <[email protected]> Co-authored-by: nirgur <[email protected]>
- Loading branch information
1 parent
a49be2b
commit d29e1f4
Showing
7 changed files
with
193 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/widgets/user-profile-widget/src/lib/widget/api/sdk/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
...get/src/lib/widget/mixins/initMixin/initComponentsMixins/initUserCustomAttributesMixin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import { | ||
FlowDriver, | ||
ModalDriver, | ||
UserAttributeDriver, | ||
} from '@descope/sdk-component-drivers'; | ||
import { | ||
compose, | ||
createSingletonMixin, | ||
withMemCache, | ||
} from '@descope/sdk-helpers'; | ||
import { loggerMixin, modalMixin } from '@descope/sdk-mixins'; | ||
import { AttributeTypeName } from '../../../api/types'; | ||
import { getUserCustomAttrs } from '../../../state/selectors'; | ||
import { createFlowTemplate } from '../../helpers'; | ||
import { stateManagementMixin } from '../../stateManagementMixin'; | ||
import { initWidgetRootMixin } from './initWidgetRootMixin'; | ||
|
||
export const initUserCustomAttributesMixin = createSingletonMixin( | ||
<T extends CustomElementConstructor>(superclass: T) => | ||
class UserCustomAttributesMixinClass extends compose( | ||
stateManagementMixin, | ||
loggerMixin, | ||
initWidgetRootMixin, | ||
modalMixin, | ||
)(superclass) { | ||
// flow Id is key in all maps | ||
#editModals: Record<string, ModalDriver> = {}; | ||
|
||
#editFlows: Record<string, FlowDriver> = {}; | ||
|
||
#deleteModals: Record<string, ModalDriver> = {}; | ||
|
||
#deleteFlows: Record<string, FlowDriver> = {}; | ||
|
||
static getFormattedValue(type: string, val: any) { | ||
if (type === AttributeTypeName.DATE && val) { | ||
// to full date time | ||
return new Date(val).toLocaleString(); | ||
} | ||
if (type === AttributeTypeName.BOOLEAN && val !== undefined) { | ||
return !val ? 'False' : 'True'; | ||
} | ||
return (val || '').toString(); | ||
} | ||
|
||
#initEditModalContent(flowId: string) { | ||
this.#editModals[flowId]?.setContent( | ||
createFlowTemplate({ | ||
projectId: this.projectId, | ||
flowId, | ||
baseUrl: this.baseUrl, | ||
baseStaticUrl: this.baseStaticUrl, | ||
}), | ||
); | ||
this.#editFlows[flowId]?.onSuccess(() => { | ||
this.#editModals[flowId]?.close(); | ||
this.actions.getMe(); | ||
}); | ||
} | ||
|
||
// have 2 init functions for edit and delete modals in order to keep the same standards as the email/phone/name mixin | ||
#initDeleteModalContent(flowId: string) { | ||
this.#deleteModals[flowId]?.setContent( | ||
createFlowTemplate({ | ||
projectId: this.projectId, | ||
flowId, | ||
baseUrl: this.baseUrl, | ||
baseStaticUrl: this.baseStaticUrl, | ||
}), | ||
); | ||
this.#deleteFlows[flowId]?.onSuccess(() => { | ||
this.#deleteModals[flowId]?.close(); | ||
this.actions.getMe(); | ||
}); | ||
} | ||
|
||
#updateCustomValueUserAttrs = withMemCache( | ||
(userCustomAttributes: ReturnType<typeof getUserCustomAttrs>) => { | ||
const allCustomAttributesComponents = | ||
this.shadowRoot?.querySelectorAll( | ||
'descope-user-attribute[data-id^="customAttributes."]', | ||
); | ||
|
||
Array.from(allCustomAttributesComponents).forEach((nodeEle) => { | ||
const attrName = nodeEle.getAttribute('data-id'); | ||
const customAttrName = attrName.replace('customAttributes.', ''); | ||
const type = | ||
nodeEle.getAttribute('data-type') || AttributeTypeName.TEXT; | ||
const val = userCustomAttributes[customAttrName]; | ||
|
||
const compInstance = new UserAttributeDriver(nodeEle, { | ||
logger: this.logger, | ||
}); | ||
|
||
compInstance.value = | ||
UserCustomAttributesMixinClass.getFormattedValue(type, val); | ||
|
||
this.#initEditFlow(nodeEle, customAttrName, compInstance); | ||
this.#initDeleteFlow(nodeEle, customAttrName, compInstance); | ||
}); | ||
}, | ||
); | ||
|
||
#initEditFlow( | ||
nodeEle: Element, | ||
customAttrName: string, | ||
compInstance: UserAttributeDriver, | ||
) { | ||
const editFlowId = nodeEle.getAttribute('edit-flow-id'); | ||
if (editFlowId) { | ||
this.#editModals[editFlowId] = this.createModal({ | ||
'data-id': `edit-${customAttrName}`, | ||
}); | ||
|
||
this.#editFlows[editFlowId] = new FlowDriver( | ||
() => | ||
this.#editModals[editFlowId]?.ele?.querySelector('descope-wc'), | ||
{ logger: this.logger }, | ||
); | ||
this.#editModals[editFlowId].afterClose = | ||
this.#initEditModalContent.bind(this, editFlowId); | ||
|
||
compInstance.onEditClick(() => { | ||
this.#editModals?.[editFlowId]?.open(); | ||
}); | ||
|
||
this.#initEditModalContent(editFlowId); | ||
} | ||
} | ||
|
||
#initDeleteFlow( | ||
nodeEle: Element, | ||
customAttrName: string, | ||
compInstance: UserAttributeDriver, | ||
) { | ||
const deleteFlowId = nodeEle.getAttribute('delete-flow-id'); | ||
if (deleteFlowId) { | ||
this.#deleteModals[deleteFlowId] = this.createModal({ | ||
'data-id': `delete-${customAttrName}`, | ||
}); | ||
|
||
this.#deleteFlows[deleteFlowId] = new FlowDriver( | ||
() => | ||
this.#deleteModals[deleteFlowId]?.ele?.querySelector( | ||
'descope-wc', | ||
), | ||
{ logger: this.logger }, | ||
); | ||
this.#deleteModals[deleteFlowId].afterClose = | ||
this.#initDeleteModalContent.bind(this, deleteFlowId); | ||
|
||
compInstance.onDeleteClick(() => { | ||
this.#deleteModals?.[deleteFlowId]?.open(); | ||
}); | ||
|
||
this.#initDeleteModalContent(deleteFlowId); | ||
} | ||
} | ||
|
||
async onWidgetRootReady() { | ||
await super.onWidgetRootReady?.(); | ||
|
||
this.#updateCustomValueUserAttrs(getUserCustomAttrs(this.state)); | ||
|
||
this.subscribe( | ||
this.#updateCustomValueUserAttrs.bind(this), | ||
getUserCustomAttrs, | ||
); | ||
} | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.