diff --git a/.cursor/rules/code-style.mdc b/.cursor/rules/code-style.mdc index 8b2440fea2..c23c952844 100644 --- a/.cursor/rules/code-style.mdc +++ b/.cursor/rules/code-style.mdc @@ -30,6 +30,18 @@ type ButtonProps = {}; // Component props suffix with 'Props' // ✅ Files and directories - kebab-case // user-profile.component.tsx // user-profile.styles.ts + +// ❌ NEVER use abbreviations in variable names +// Bad +const users = data.map((u) => u.name); +const field = items.find((f) => f.id === id); + +// Good +const users = data.map((user) => user.name); +const field = items.find((item) => item.id === id); +const fieldMetadata = inlineFields.find( + (fieldMetadataItem) => fieldMetadataItem.name === fieldName, +); ``` ## Import Organization @@ -59,11 +71,11 @@ const processUserData = ( ): ProcessedUser => { const processedUser = transformUserData(user); applyOptions(processedUser, options); - + if (callback) { callback(processedUser); } - + return processedUser; }; ``` @@ -71,7 +83,7 @@ const processUserData = ( ## Comments ```typescript // ✅ Use short-form comments, NOT JSDoc blocks -// ✅ Explain business logic and non-obvious intentions +// ✅ Explain business logic and non-obvious intentions (WHY, not WHAT) // Apply 15% discount for premium users with orders > $100 const discount = isPremiumUser && orderTotal > 100 ? 0.15 : 0; @@ -85,12 +97,55 @@ const calculateTotalPrice = (basePrice: number): number => { // Implementation }; +// ❌ AVOID obvious comments that just describe what code does +// Bad: Get all inline fields dynamically +const { inlineFieldMetadataItems } = useFieldListFieldMetadataItems({...}); + +// Bad: Define standard fields in display order +const standardFieldOrder = ['startsAt', 'endsAt', 'conferenceLink']; + +// Bad: Split fields into standard and custom +const standardFields = standardFieldOrder.map(...) + +// ✅ GOOD: Only comment if explaining non-obvious business logic +// Calendar events display standard fields first, then custom fields after participants +// to maintain consistency with the legacy UI behavior +const standardFields = standardFieldOrder.map(...) + // ❌ AVOID JSDoc blocks - use short comments instead /** * This style is NOT preferred in this codebase */ ``` +**Comment Guidelines:** +- **DO** comment complex business rules or domain-specific logic +- **DO** comment non-obvious algorithmic decisions +- **DO** add TODOs for future improvements +- **DON'T** comment obvious variable declarations or function calls +- **DON'T** comment what is already clear from well-named variables/functions +- **DON'T** add comments that just repeat what the code says + +## Utility Helpers +```typescript +// ✅ Use existing utility helpers instead of manual checks +import { isDefined } from 'twenty-shared/utils'; +import { isNonEmptyString, isNonEmptyArray } from '@sniptt/guards'; + +// ❌ Manual type guards +const validItems = items.filter((item): item is Item => item !== undefined); +const hasValue = value !== null && value !== undefined; + +// ✅ Use utility helpers +const validItems = items.filter(isDefined); +const hasValue = isDefined(value); + +// Other useful helpers: +// - isDefined(value) - checks !== null && !== undefined +// - isNonEmptyString(value) - checks string is defined and not empty +// - isNonEmptyArray(value) - checks array is defined and has items +``` + ## Security Patterns ```typescript // ✅ CSV Export: Always apply security first, then formatting diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx index 29e4bda862..4cd8c53bda 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx @@ -5,16 +5,18 @@ import { CalendarEventParticipantsResponseStatus } from '@/activities/calendar/c import { type CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly'; +import { useFieldListFieldMetadataItems } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; +import { isDefined } from 'twenty-shared/utils'; import { Chip, ChipAccent, ChipSize, ChipVariant } from 'twenty-ui/components'; import { IconCalendarEvent } from 'twenty-ui/display'; -import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; type CalendarEventDetailsProps = { @@ -80,7 +82,13 @@ export const CalendarEventDetails = ({ objectNameSingular: CoreObjectNameSingular.CalendarEvent, }); - const fieldsToDisplay = [ + const { inlineFieldMetadataItems } = useFieldListFieldMetadataItems({ + objectNameSingular: CoreObjectNameSingular.CalendarEvent, + showRelationSections: false, + excludeCreatedAtAndUpdatedAt: true, + }); + + const standardFieldOrder = [ 'startsAt', 'endsAt', 'conferenceLink', @@ -88,9 +96,16 @@ export const CalendarEventDetails = ({ 'description', ]; - const fieldsByName = mapArrayToObject( - objectMetadataItem.fields, - ({ name }) => name, + const standardFields = standardFieldOrder + .map((fieldName) => + inlineFieldMetadataItems.find( + (fieldMetadataItem) => fieldMetadataItem.name === fieldName, + ), + ) + .filter(isDefined); + + const customFields = inlineFieldMetadataItems.filter( + (field) => field.isCustom && !standardFieldOrder.includes(field.name), ); const { calendarEventParticipants } = calendarEvent; @@ -100,14 +115,14 @@ export const CalendarEventDetails = ({ objectMetadataId: objectMetadataItem.id, }); - const Fields = fieldsToDisplay.map((fieldName) => ( - + const renderField = (fieldMetadataItem: FieldMetadataItem) => ( + - )); + ); return ( @@ -154,13 +169,14 @@ export const CalendarEventDetails = ({ - {Fields.slice(0, 2)} + {standardFields.slice(0, 2).map(renderField)} {calendarEventParticipants && ( )} - {Fields.slice(2)} + {standardFields.slice(2).map(renderField)} + {customFields.map(renderField)} );