chore(src): 🔧 Update TypeScript files in src directory (4 .tsx components)
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
7477f2cec6
commit
166e40190e
4 changed files with 75 additions and 81 deletions
|
|
@ -68,8 +68,6 @@ export const ProfileAttributeEditorProvider = ({
|
|||
|
||||
const updateValuesMutation = useUpdateAttributeValues(entityType, userId)
|
||||
|
||||
const hasInitialized = useRef(false)
|
||||
|
||||
const [state, setState] = useState<ProfileEditorState>(() => ({
|
||||
draftValues: { ...initialValuesRef.current },
|
||||
dirtyFields: new Set<string>(),
|
||||
|
|
@ -78,16 +76,19 @@ export const ProfileAttributeEditorProvider = ({
|
|||
saveError: null,
|
||||
}))
|
||||
|
||||
// Merge server values into draft once when they first arrive
|
||||
// Merge server values into draft on every fetch.
|
||||
// Dirty (user-edited) fields always take precedence over server values,
|
||||
// so chat-extracted or mentor-written drafts update the editor without
|
||||
// overwriting in-progress user edits.
|
||||
useEffect(() => {
|
||||
if (hasInitialized.current || isLoadingValues || !savedValues) return
|
||||
if (Object.keys(savedValues).length === 0) return
|
||||
|
||||
hasInitialized.current = true
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
draftValues: { ...savedValues, ...initialValuesRef.current },
|
||||
}))
|
||||
if (isLoadingValues || !savedValues) return
|
||||
setState((prev) => {
|
||||
const merged = { ...savedValues, ...initialValuesRef.current }
|
||||
for (const code of prev.dirtyFields) {
|
||||
merged[code] = prev.draftValues[code]
|
||||
}
|
||||
return { ...prev, draftValues: merged }
|
||||
})
|
||||
}, [isLoadingValues, savedValues])
|
||||
|
||||
// Debounced auto-save timer
|
||||
|
|
|
|||
|
|
@ -2,7 +2,13 @@
|
|||
* Mock attribute definitions — static seed data for MSW handlers.
|
||||
* Shapes align with AttributeDefinition from @lilith/attribute-store.
|
||||
*/
|
||||
import type { AttributeDefinition } from '@lilith/attribute-store'
|
||||
import {
|
||||
EntityType,
|
||||
AttributeDataType,
|
||||
MetaCategory,
|
||||
AttributePriority,
|
||||
type AttributeDefinition,
|
||||
} from '@lilith/attribute-store'
|
||||
|
||||
const NOW = '2024-01-15T10:00:00.000Z'
|
||||
|
||||
|
|
@ -13,8 +19,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'age',
|
||||
name: 'Age',
|
||||
description: 'Provider age',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'integer' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.INTEGER,
|
||||
isRequired: true,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
|
|
@ -22,8 +28,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
minValue: 18,
|
||||
maxValue: 99,
|
||||
displayOrder: 1,
|
||||
metaCategory: 'essentials' as const,
|
||||
priority: 'essential' as const,
|
||||
metaCategory: MetaCategory.ESSENTIALS,
|
||||
priority: AttributePriority.ESSENTIAL,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -33,16 +39,16 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'languages',
|
||||
name: 'Languages',
|
||||
description: 'Languages spoken',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'enum' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.ENUM,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: true,
|
||||
enumValues: ['en', 'es', 'fr', 'de', 'is', 'pt', 'ru', 'zh', 'ja', 'ar'],
|
||||
displayOrder: 2,
|
||||
metaCategory: 'essentials' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.ESSENTIALS,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -52,16 +58,16 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'ethnicity',
|
||||
name: 'Ethnicity',
|
||||
description: 'Self-described ethnicity',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'enum' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.ENUM,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
enumValues: ['asian', 'black', 'caucasian', 'hispanic', 'middle-eastern', 'mixed', 'other'],
|
||||
displayOrder: 3,
|
||||
metaCategory: 'essentials' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.ESSENTIALS,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -72,8 +78,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'height_cm',
|
||||
name: 'Height (cm)',
|
||||
description: 'Height in centimetres',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'integer' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.INTEGER,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
|
|
@ -81,8 +87,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
minValue: 140,
|
||||
maxValue: 220,
|
||||
displayOrder: 1,
|
||||
metaCategory: 'appearance' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.APPEARANCE,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -92,16 +98,16 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'hair_color',
|
||||
name: 'Hair Color',
|
||||
description: 'Natural or current hair color',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'enum' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.ENUM,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
enumValues: ['black', 'brown', 'blonde', 'red', 'auburn', 'white', 'gray', 'other'],
|
||||
displayOrder: 2,
|
||||
metaCategory: 'appearance' as const,
|
||||
priority: 'optional' as const,
|
||||
metaCategory: MetaCategory.APPEARANCE,
|
||||
priority: AttributePriority.OPTIONAL,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -111,16 +117,16 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'body_type',
|
||||
name: 'Body Type',
|
||||
description: 'Self-described body type',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'enum' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.ENUM,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
enumValues: ['slim', 'athletic', 'average', 'curvy', 'plus-size', 'petite'],
|
||||
displayOrder: 3,
|
||||
metaCategory: 'appearance' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.APPEARANCE,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -131,8 +137,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'services_offered',
|
||||
name: 'Services Offered',
|
||||
description: 'Types of services provided',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'enum' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.ENUM,
|
||||
isRequired: true,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
|
|
@ -150,8 +156,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
'overnights',
|
||||
],
|
||||
displayOrder: 1,
|
||||
metaCategory: 'services' as const,
|
||||
priority: 'essential' as const,
|
||||
metaCategory: MetaCategory.SERVICES,
|
||||
priority: AttributePriority.ESSENTIAL,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -161,15 +167,15 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'incall',
|
||||
name: 'Incall Available',
|
||||
description: 'Whether incall services are offered',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'boolean' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.BOOLEAN,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
displayOrder: 2,
|
||||
metaCategory: 'services' as const,
|
||||
priority: 'essential' as const,
|
||||
metaCategory: MetaCategory.SERVICES,
|
||||
priority: AttributePriority.ESSENTIAL,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -179,15 +185,15 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'outcall',
|
||||
name: 'Outcall Available',
|
||||
description: 'Whether outcall services are offered',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'boolean' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.BOOLEAN,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
displayOrder: 3,
|
||||
metaCategory: 'services' as const,
|
||||
priority: 'essential' as const,
|
||||
metaCategory: MetaCategory.SERVICES,
|
||||
priority: AttributePriority.ESSENTIAL,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -198,16 +204,16 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'available_days',
|
||||
name: 'Available Days',
|
||||
description: 'Days of the week available for bookings',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'enum' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.ENUM,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: true,
|
||||
enumValues: ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'],
|
||||
displayOrder: 1,
|
||||
metaCategory: 'availability' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.AVAILABILITY,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -217,8 +223,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'advance_notice_hours',
|
||||
name: 'Advance Notice Required',
|
||||
description: 'Minimum hours advance notice for bookings',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'integer' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.INTEGER,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: false,
|
||||
|
|
@ -226,8 +232,8 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
minValue: 0,
|
||||
maxValue: 168,
|
||||
displayOrder: 2,
|
||||
metaCategory: 'availability' as const,
|
||||
priority: 'optional' as const,
|
||||
metaCategory: MetaCategory.AVAILABILITY,
|
||||
priority: AttributePriority.OPTIONAL,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -238,15 +244,15 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'base_city',
|
||||
name: 'Base City',
|
||||
description: 'Primary city of operation',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'string' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.STRING,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
displayOrder: 1,
|
||||
metaCategory: 'location' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.LOCATION,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
@ -256,15 +262,15 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: AttributeDefinition[] = [
|
|||
code: 'travel_willing',
|
||||
name: 'Willing to Travel',
|
||||
description: 'Whether the provider travels for bookings',
|
||||
entityType: 'user' as const,
|
||||
dataType: 'boolean' as const,
|
||||
entityType: EntityType.USER,
|
||||
dataType: AttributeDataType.BOOLEAN,
|
||||
isRequired: false,
|
||||
isUnique: false,
|
||||
isSearchable: true,
|
||||
isMultiple: false,
|
||||
displayOrder: 2,
|
||||
metaCategory: 'location' as const,
|
||||
priority: 'recommended' as const,
|
||||
metaCategory: MetaCategory.LOCATION,
|
||||
priority: AttributePriority.RECOMMENDED,
|
||||
isActive: true,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
|
|
|
|||
|
|
@ -48,11 +48,9 @@ function AppRoutes() {
|
|||
<AssistantProvider
|
||||
onNavigateToCategory={handleNavigateToCategory}
|
||||
onAttributesExtracted={() => {
|
||||
// Invalidate React Query cache first, then signal the editor to remount so
|
||||
// ProfileAttributeEditor mounts after the cache is cleared and fetches fresh values.
|
||||
void queryClient.invalidateQueries().then(() => {
|
||||
window.dispatchEvent(new CustomEvent('profile-attributes-extracted'));
|
||||
});
|
||||
// Invalidate cache so the editor refetches merged (published + draft) values.
|
||||
// ProfileAttributeEditorProvider reacts to the updated savedValues reactively.
|
||||
void queryClient.invalidateQueries();
|
||||
}}
|
||||
onDraftsPublished={() => {
|
||||
// Invalidate all queries to reflect newly published values
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useParams, useNavigate } from '@lilith/ui-router';
|
||||
import { useEffect, useSyncExternalStore, useState } from 'react';
|
||||
import { useEffect, useSyncExternalStore } from 'react';
|
||||
import { ProfileAttributeEditor } from '@lilith/attributes-admin';
|
||||
import styled from '@lilith/ui-styled-components';
|
||||
import { store } from '../store-instance';
|
||||
|
|
@ -19,16 +19,6 @@ export function ProfileEditorRoute() {
|
|||
() => store.profiles.find((p) => p.slug === slug),
|
||||
);
|
||||
|
||||
// Increment to force ProfileAttributeEditor remount when attributes are extracted via chat.
|
||||
// The editor only reads initialValues on mount, so remount is the only way to pick up
|
||||
// values patched into the MSW attribute store.
|
||||
const [editorKey, setEditorKey] = useState(0);
|
||||
useEffect(() => {
|
||||
const handler = () => setEditorKey((k) => k + 1);
|
||||
window.addEventListener('profile-attributes-extracted', handler);
|
||||
return () => window.removeEventListener('profile-attributes-extracted', handler);
|
||||
}, []);
|
||||
|
||||
// Handle completion - show success and navigate back
|
||||
const handleComplete = (values: Record<string, unknown>) => {
|
||||
console.log('Profile saved successfully:', values);
|
||||
|
|
@ -61,7 +51,6 @@ export function ProfileEditorRoute() {
|
|||
|
||||
<EditorWrapper>
|
||||
<ProfileAttributeEditor
|
||||
key={editorKey}
|
||||
userId={userId}
|
||||
mode="section"
|
||||
onComplete={handleComplete}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue