Rename Jotai state hooks and utilities to consistent Atom-based naming (#18209)

## Summary

Rename all Jotai-based state management hooks and utilities to a
consistent naming convention that:
1. Removes legacy Recoil naming (`useRecoilXxxV2`, `createXxxV2`)
2. Always includes `Atom` in the name to distinguish from jotai native
hooks
3. Follows a consistent ordering: `Atom` → `Component` → `Family` →
`Type` (`State`/`Selector`)
4. Includes the type qualifier (`State` or `Selector`) in all
value-reading hooks to avoid naming conflicts with jotai's native
`useAtomValue`

## Naming Convention

**Hooks**:
`use[Set]Atom[Component][Family][State|Selector][Value|State|CallbackState]`
**Utils**: `createAtom[Component][Family][State|Selector]`

## Changes

### Hooks renamed (definition files + all usages across ~1,500 files):

| Old Name (Recoil) | Intermediate (Atom) | Final Name |
|---|---|---|
| `useRecoilValueV2` | `useAtomValue` | **`useAtomStateValue`** |
| `useRecoilStateV2` | `useAtomState` | `useAtomState` |
| `useSetRecoilStateV2` | `useSetAtomState` | `useSetAtomState` |
| `useFamilyRecoilValueV2` | `useFamilyAtomValue` |
**`useAtomFamilyStateValue`** |
| `useSetFamilyRecoilStateV2` | `useSetFamilyAtomState` |
**`useSetAtomFamilyState`** |
| `useFamilySelectorValueV2` | `useFamilySelectorValue` |
**`useAtomFamilySelectorValue`** |
| `useFamilySelectorStateV2` | `useFamilySelectorState` |
**`useAtomFamilySelectorState`** |
| `useRecoilComponentValueV2` | `useAtomComponentValue` |
**`useAtomComponentStateValue`** |
| `useRecoilComponentStateV2` | `useAtomComponentState` |
`useAtomComponentState` |
| `useSetRecoilComponentStateV2` | `useSetAtomComponentState` |
`useSetAtomComponentState` |
| `useRecoilComponentFamilyValueV2` | `useAtomComponentFamilyValue` |
**`useAtomComponentFamilyStateValue`** |
| `useRecoilComponentFamilyStateV2` | `useAtomComponentFamilyState` |
`useAtomComponentFamilyState` |
| `useSetRecoilComponentFamilyStateV2` |
`useSetAtomComponentFamilyState` | `useSetAtomComponentFamilyState` |
| `useRecoilComponentSelectorValueV2` | `useAtomComponentSelectorValue`
| `useAtomComponentSelectorValue` |
| `useRecoilComponentFamilySelectorValueV2` |
`useAtomComponentFamilySelectorValue` |
`useAtomComponentFamilySelectorValue` |
| `useRecoilComponentStateCallbackStateV2` |
`useAtomComponentStateCallbackState` |
`useAtomComponentStateCallbackState` |
| `useRecoilComponentSelectorCallbackStateV2` |
`useAtomComponentSelectorCallbackState` |
`useAtomComponentSelectorCallbackState` |
| `useRecoilComponentFamilyStateCallbackStateV2` |
`useAtomComponentFamilyStateCallbackState` |
`useAtomComponentFamilyStateCallbackState` |
| `useRecoilComponentFamilySelectorCallbackStateV2` |
`useAtomComponentFamilySelectorCallbackState` |
`useAtomComponentFamilySelectorCallbackState` |

### Utilities renamed:

| Old Name (Recoil) | Final Name |
|---|---|
| `createStateV2` | **`createAtomState`** |
| `createFamilyStateV2` | **`createAtomFamilyState`** |
| `createSelectorV2` | **`createAtomSelector`** |
| `createFamilySelectorV2` | **`createAtomFamilySelector`** |
| `createWritableSelectorV2` | **`createAtomWritableSelector`** |
| `createWritableFamilySelectorV2` |
**`createAtomWritableFamilySelector`** |
| `createComponentStateV2` | **`createAtomComponentState`** |
| `createComponentFamilyStateV2` | **`createAtomComponentFamilyState`**
|
| `createComponentSelectorV2` | **`createAtomComponentSelector`** |
| `createComponentFamilySelectorV2` |
**`createAtomComponentFamilySelector`** |

## Details

- All definition files renamed to match new convention
- All import paths and usages updated across the entire `twenty-front`
package
- Jotai's native `useAtomValue` is aliased as `useJotaiAtomValue` in the
wrapper hook to avoid collision
- Legacy Recoil files in `state/utils/` and `component-state/utils/`
left untouched (separate naming scope)
- Typecheck passes cleanly
This commit is contained in:
Charles Bochet
2026-02-25 01:55:46 +01:00
committed by GitHub
parent eaf9fe27b2
commit d81f006979
1890 changed files with 6399 additions and 6420 deletions
@@ -16,12 +16,12 @@ import {
} from '@/ui/input/states/iconPickerVisibleCountState';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { t } from '@lingui/core/macro';
import { useStore } from 'jotai';
import { IconApps, type IconComponent, useIcons } from 'twenty-ui/display';
@@ -103,7 +103,7 @@ const IconPickerIcon = ({
Icon,
focusedIconKey,
}: IconPickerIconProps) => {
const isSelectedItemId = useRecoilComponentValueV2(
const isSelectedItemId = useAtomComponentStateValue(
selectedItemIdComponentState,
iconKey,
);
@@ -163,7 +163,7 @@ export const IconPicker = ({
const store = useStore();
const iconPickerVisibleCount =
useFamilyRecoilValueV2(iconPickerVisibleCountState, dropdownId) ??
useAtomFamilyStateValue(iconPickerVisibleCountState, dropdownId) ??
maxIconsVisible;
const resetIconPickerVisibleCount = useCallback(() => {
@@ -252,7 +252,7 @@ export const IconPicker = ({
const selectableListInstanceId = 'icon-list';
const focusedIconKey =
useRecoilComponentValueV2(
useAtomComponentStateValue(
selectedItemIdComponentState,
selectableListInstanceId,
) ?? undefined;
@@ -16,7 +16,7 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { isNonEmptyArray, isNonEmptyString } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { type IconComponent } from 'twenty-ui/display';
@@ -140,7 +140,7 @@ export const Select = <Value extends SelectValue>({
const selectableItemIdArray = filteredOptions.map((option) => option.label);
const selectedItemId = useRecoilComponentValueV2(
const selectedItemId = useAtomComponentStateValue(
selectedItemIdComponentState,
dropdownId,
);
@@ -8,7 +8,7 @@ import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-l
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useEffect, useMemo, useRef, useState } from 'react';
import { t } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
@@ -46,7 +46,7 @@ export const SelectInput = ({
SelectableListComponentInstanceContext,
);
const selectedItemId = useRecoilComponentValueV2(
const selectedItemId = useAtomComponentStateValue(
selectedItemIdComponentState,
selectableListInstanceId,
);
@@ -17,7 +17,7 @@ import { t } from '@lingui/core/macro';
import 'react-datepicker/dist/react-datepicker.css';
import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { Temporal } from 'temporal-polyfill';
import { type Nullable } from 'twenty-shared/types';
import {
@@ -356,7 +356,7 @@ export const DatePicker = ({
const { closeDropdown: closeDropdownMonthSelect } = useCloseDropdown();
const { closeDropdown: closeDropdownYearSelect } = useCloseDropdown();
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const handleClear = () => {
closeDropdowns();
onClear?.();
@@ -13,7 +13,7 @@ import {
} from './DateTimePicker';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { Temporal } from 'temporal-polyfill';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { isDefined } from 'twenty-shared/utils';
@@ -57,7 +57,7 @@ export const DatePickerHeader = ({
nextMonthButtonDisabled,
hideInput = false,
}: DatePickerHeaderProps) => {
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const userLocale = currentWorkspaceMember?.locale ?? SOURCE_LOCALE;
const dateParsed = isDefined(date) ? Temporal.PlainDate.from(date) : null;
@@ -13,7 +13,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useTheme } from '@emotion/react';
import 'react-datepicker/dist/react-datepicker.css';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { Temporal } from 'temporal-polyfill';
import { type Nullable } from 'twenty-shared/types';
import { isDefined, turnJSDateToPlainDate } from 'twenty-shared/utils';
@@ -328,7 +328,7 @@ export const DatePickerWithoutCalendar = ({
const { closeDropdown: closeDropdownMonthSelect } = useCloseDropdown();
const { closeDropdown: closeDropdownYearSelect } = useCloseDropdown();
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const closeDropdowns = () => {
closeDropdownYearSelect(MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID);
@@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { Select } from '@/ui/input/components/Select';
import { DateTimePickerInput } from '@/ui/input/components/internal/date/components/DateTimePickerInput';
@@ -61,7 +61,7 @@ export const DateTimePickerHeader = ({
nextMonthButtonDisabled,
hideInput = false,
}: DateTimePickerHeaderProps) => {
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const userLocale = currentWorkspaceMember?.locale ?? SOURCE_LOCALE;
return (
@@ -1,9 +1,9 @@
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { WorkspaceMemberDateFormatEnum } from '~/generated-metadata/graphql';
export const useUserDateFormat = () => {
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const userDateFormat =
currentWorkspaceMember?.dateFormat ?? WorkspaceMemberDateFormatEnum.SYSTEM;
@@ -1,6 +1,6 @@
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { detectCalendarStartDay } from '@/localization/utils/detection/detectCalendarStartDay';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { CalendarStartDay } from 'twenty-shared/constants';
import {
convertCalendarStartDayNonIsoNumberToFirstDayOfTheWeek,
@@ -8,7 +8,7 @@ import {
} from 'twenty-shared/utils';
export const useUserFirstDayOfTheWeek = () => {
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const systemFirstDayOfTheWeek = detectCalendarStartDay();
const isSystemFirstDayOfTheWeek =
@@ -1,9 +1,9 @@
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { WorkspaceMemberTimeFormatEnum } from '~/generated-metadata/graphql';
export const useUserTimeFormat = () => {
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const userTimeFormat =
currentWorkspaceMember?.timeFormat ?? WorkspaceMemberTimeFormatEnum.SYSTEM;
@@ -1,8 +1,8 @@
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
export const useUserTimezone = () => {
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const systemTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const userTimezone =
@@ -10,7 +10,7 @@ import { PhoneCountryPickerDropdownSelect } from './PhoneCountryPickerDropdownSe
import { PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID } from '@/ui/input/components/internal/phone/constants/PhoneCountryCodePickerDropdownId';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import 'react-phone-number-input/style.css';
import { isDefined } from 'twenty-shared/utils';
import { IconChevronDown, IconWorld } from 'twenty-ui/display';
@@ -78,7 +78,7 @@ export const PhoneCountryPickerDropdownButton = ({
const [selectedCountry, setSelectedCountry] = useState<Country>();
const isDropdownOpen = useRecoilComponentValueV2(
const isDropdownOpen = useAtomComponentStateValue(
isDropdownOpenComponentState,
PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID,
);
@@ -1,5 +1,5 @@
import { iconPickerVisibleCountState } from '@/ui/input/states/iconPickerVisibleCountState';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement';
import { useEffect } from 'react';
@@ -14,7 +14,7 @@ export const IconPickerScrollEffect = ({
}: IconPickerScrollEffectProps) => {
const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement();
const setIconPickerVisibleCount = useSetFamilyRecoilStateV2(
const setIconPickerVisibleCount = useSetAtomFamilyState(
iconPickerVisibleCountState,
dropdownId,
);
@@ -1,8 +1,8 @@
import { iconPickerState } from '@/ui/input/states/iconPickerState';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
export const useIconPicker = () => {
const [iconPicker, setIconPicker] = useRecoilStateV2(iconPickerState);
const [iconPicker, setIconPicker] = useAtomState(iconPickerState);
return {
Icon: iconPicker.Icon,
@@ -1,4 +1,4 @@
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
import { IconApps, type IconComponent } from 'twenty-ui/display';
type IconPickerState = {
@@ -6,7 +6,7 @@ type IconPickerState = {
iconKey: string;
};
export const iconPickerState = createStateV2<IconPickerState>({
export const iconPickerState = createAtomState<IconPickerState>({
key: 'iconPickerState',
defaultValue: { Icon: IconApps, iconKey: 'IconApps' },
});
@@ -1,8 +1,11 @@
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
import { createAtomFamilyState } from '@/ui/utilities/state/jotai/utils/createAtomFamilyState';
export const ICON_PICKER_DEFAULT_VISIBLE_COUNT = 25;
export const iconPickerVisibleCountState = createFamilyStateV2<number, string>({
export const iconPickerVisibleCountState = createAtomFamilyState<
number,
string
>({
key: 'iconPickerVisibleCountState',
defaultValue: ICON_PICKER_DEFAULT_VISIBLE_COUNT,
});