diff --git a/front/src/modules/auth/components/RequireOnboarded.tsx b/front/src/modules/auth/components/RequireOnboarded.tsx index d72ae84d1..d18fc2918 100644 --- a/front/src/modules/auth/components/RequireOnboarded.tsx +++ b/front/src/modules/auth/components/RequireOnboarded.tsx @@ -47,7 +47,7 @@ export function RequireOnboarded({ } }, [onboardingStatus, navigate]); - if (onboardingStatus !== OnboardingStatus.Completed) { + if (onboardingStatus && onboardingStatus !== OnboardingStatus.Completed) { return ( diff --git a/front/src/modules/auth/hooks/useAuth.ts b/front/src/modules/auth/hooks/useAuth.ts index bfe17b25a..dbb061101 100644 --- a/front/src/modules/auth/hooks/useAuth.ts +++ b/front/src/modules/auth/hooks/useAuth.ts @@ -59,11 +59,10 @@ export function useAuth() { setTokenPair(verifyResult.data?.verify.tokens); setIsAuthenticating(false); - setCurrentUser(verifyResult.data?.verify.user); return verifyResult.data?.verify; }, - [setCurrentUser, setIsAuthenticating, setTokenPair, verify], + [setIsAuthenticating, setTokenPair, verify], ); const handleLogin = useCallback( @@ -77,7 +76,8 @@ export function useAuth() { const handleLogout = useCallback(() => { setTokenPair(null); - }, [setTokenPair]); + setCurrentUser(null); + }, [setTokenPair, setCurrentUser]); const handleSignUp = useCallback( async (email: string, password: string, workspaceInviteHash?: string) => { diff --git a/front/src/modules/auth/hooks/useOnboardingStatus.ts b/front/src/modules/auth/hooks/useOnboardingStatus.ts index 5b9d8499f..68ec6813c 100644 --- a/front/src/modules/auth/hooks/useOnboardingStatus.ts +++ b/front/src/modules/auth/hooks/useOnboardingStatus.ts @@ -8,9 +8,10 @@ import { OnboardingStatus, } from '../utils/getOnboardingStatus'; -export function useOnboardingStatus(): OnboardingStatus { +export function useOnboardingStatus(): OnboardingStatus | undefined { const [currentUser] = useRecoilState(currentUserState); const isLoggedIn = useIsLogged(); + const onboardingStatus = useMemo( () => getOnboardingStatus(isLoggedIn, currentUser), [currentUser, isLoggedIn], diff --git a/front/src/modules/auth/utils/getOnboardingStatus.ts b/front/src/modules/auth/utils/getOnboardingStatus.ts index deb2d7dc7..a5613edda 100644 --- a/front/src/modules/auth/utils/getOnboardingStatus.ts +++ b/front/src/modules/auth/utils/getOnboardingStatus.ts @@ -11,9 +11,15 @@ export function getOnboardingStatus( isLoggedIn: boolean, currentUser: CurrentUser | null, ) { - if (!isLoggedIn || !currentUser) { + if (!isLoggedIn) { return OnboardingStatus.OngoingUserCreation; } + + // if the user has not been fetched yet, we can't know the onboarding status + if (!currentUser) { + return undefined; + } + if (!currentUser.workspaceMember?.workspace.displayName) { return OnboardingStatus.OngoingWorkspaceCreation; } diff --git a/front/src/modules/companies/components/CompanyBoardCard.tsx b/front/src/modules/companies/components/CompanyBoardCard.tsx index 32815bab1..f2a9a668b 100644 --- a/front/src/modules/companies/components/CompanyBoardCard.tsx +++ b/front/src/modules/companies/components/CompanyBoardCard.tsx @@ -114,8 +114,8 @@ export function CompanyBoardCard() { [updatePipelineProgress], ); - const handleCheckboxChange = () => { - setSelected(!selected); + const handleCheckboxChange = (checked: boolean) => { + setSelected(checked); }; if (!company || !pipelineProgress) { diff --git a/front/src/modules/ui/components/form/Checkbox.tsx b/front/src/modules/ui/components/form/Checkbox.tsx index af70f9351..cc87cd661 100644 --- a/front/src/modules/ui/components/form/Checkbox.tsx +++ b/front/src/modules/ui/components/form/Checkbox.tsx @@ -1,79 +1,98 @@ import * as React from 'react'; import styled from '@emotion/styled'; -import { IconCheck } from '@/ui/icons/index'; +import { IconCheck, IconMinus } from '@/ui/icons'; type OwnProps = { checked: boolean; indeterminate?: boolean; - onChange: () => void; + onChange: (value: boolean) => void; }; -const StyledContainer = styled.div` +const StyledInputContainer = styled.div` align-items: center; - display: flex; - justify-content: center; - position: relative; +`; - input[type='checkbox'] { - accent-color: ${({ theme }) => theme.color.blue}; +const StyledInput = styled.input<{ indeterminate?: boolean }>` + cursor: pointer; + margin: 0; + opacity: 0; + position: absolute; + z-index: 10; + + & + label { cursor: pointer; height: 14px; - margin: 2px; - user-select: none; + padding: 0; + position: relative; width: 14px; } - input[type='checkbox']::before { - background-color: ${({ theme }) => theme.background.primary}; - border: 1px solid ${({ theme }) => theme.font.color.tertiary}; - border-radius: ${({ theme }) => theme.border.radius.xs}; + & + label:before { + background: ${({ theme }) => theme.background.primary}; + border: 1px solid ${({ theme }) => theme.border.color.strong}; + border-radius: ${({ theme }) => theme.border.radius.sm}; content: ''; - display: block; + cursor: pointer; + display: inline-block; height: 12px; width: 12px; } - input[type='checkbox']:hover::before { - border: 1px solid ${({ theme }) => theme.font.color.primary}; - } - - input[type='checkbox']:checked::before { - border: 1px solid ${({ theme }) => theme.color.blue}; - } - - svg { + &:checked + label:before { background: ${({ theme }) => theme.color.blue}; - color: white; + border-color: ${({ theme }) => theme.color.blue}; + } + + & + label:before { + background: ${({ theme, indeterminate }) => + indeterminate ? theme.color.blue : theme.background.primary}; + border-color: ${({ theme, indeterminate }) => + indeterminate ? theme.color.blue : theme.border.color.inverted}; + } + + & + label > svg { height: 12px; - left: 50%; + left: 1px; position: absolute; - top: 50%; - transform: translate(-50%, -50%); + stroke: ${({ theme }) => theme.grayScale.gray0}; + top: 1px; width: 12px; } `; export function Checkbox({ checked, onChange, indeterminate }: OwnProps) { - const ref = React.useRef(null); + const [isInternalChecked, setIsInternalChecked] = React.useState(false); React.useEffect(() => { - if (ref.current === null) return; - if (typeof indeterminate === 'boolean') { - ref.current.indeterminate = !checked && indeterminate; - } - }, [ref, indeterminate, checked]); + setIsInternalChecked(checked); + }, [checked]); + + function handleChange(value: boolean) { + onChange(value); + setIsInternalChecked(!isInternalChecked); + } return ( - - + handleChange(event.target.checked)} /> - {checked && } - + + ); } diff --git a/front/src/modules/ui/components/table/CheckboxCell.tsx b/front/src/modules/ui/components/table/CheckboxCell.tsx index 9636947e8..a45ad7518 100644 --- a/front/src/modules/ui/components/table/CheckboxCell.tsx +++ b/front/src/modules/ui/components/table/CheckboxCell.tsx @@ -21,8 +21,8 @@ export function CheckboxCell() { const { currentRowSelected, setCurrentRowSelected } = useCurrentRowSelected(); - function handleContainerClick() { - handleCheckboxChange(!currentRowSelected); + function onChange(checked: boolean) { + handleCheckboxChange(checked); } function handleCheckboxChange(newCheckedValue: boolean) { @@ -33,7 +33,7 @@ export function CheckboxCell() { return ( - + ); } diff --git a/front/src/modules/ui/components/table/SelectAllCheckbox.tsx b/front/src/modules/ui/components/table/SelectAllCheckbox.tsx index 58d42da95..c89f74f18 100644 --- a/front/src/modules/ui/components/table/SelectAllCheckbox.tsx +++ b/front/src/modules/ui/components/table/SelectAllCheckbox.tsx @@ -17,18 +17,17 @@ const StyledContainer = styled.div` export const SelectAllCheckbox = () => { const { selectAllRows, allRowsSelectedStatus } = useSelectAllRows(); - function handleContainerClick() { - selectAllRows(); - } - const checked = allRowsSelectedStatus === 'all'; const indeterminate = allRowsSelectedStatus === 'some'; + function onChange(value: boolean) { + selectAllRows(); + } return ( diff --git a/front/src/modules/ui/icons/index.ts b/front/src/modules/ui/icons/index.ts index 072250a56..8f8802e88 100644 --- a/front/src/modules/ui/icons/index.ts +++ b/front/src/modules/ui/icons/index.ts @@ -15,6 +15,7 @@ export { IconColorSwatch } from '@tabler/icons-react'; export { IconX } from '@tabler/icons-react'; export { IconChevronLeft } from '@tabler/icons-react'; export { IconPlus } from '@tabler/icons-react'; +export { IconMinus } from '@tabler/icons-react'; export { IconLink } from '@tabler/icons-react'; export { IconUsers } from '@tabler/icons-react'; export { IconCalendarEvent } from '@tabler/icons-react'; diff --git a/front/src/modules/ui/tables/hooks/useSelectAllRows.ts b/front/src/modules/ui/tables/hooks/useSelectAllRows.ts index 4868236d6..5a996cda8 100644 --- a/front/src/modules/ui/tables/hooks/useSelectAllRows.ts +++ b/front/src/modules/ui/tables/hooks/useSelectAllRows.ts @@ -18,7 +18,10 @@ export function useSelectAllRows() { .getLoadable(tableRowIdsState) .valueOrThrow(); - if (allRowsSelectedStatus === 'none') { + if ( + allRowsSelectedStatus === 'none' || + allRowsSelectedStatus === 'some' + ) { for (const rowId of tableRowIds) { set(isRowSelectedFamilyState(rowId), true); } diff --git a/front/src/modules/ui/themes/border.ts b/front/src/modules/ui/themes/border.ts index 3b39817a1..22aa9ac95 100644 --- a/front/src/modules/ui/themes/border.ts +++ b/front/src/modules/ui/themes/border.ts @@ -14,6 +14,7 @@ export const borderLight = { strong: grayScale.gray25, medium: grayScale.gray20, light: grayScale.gray15, + inverted: grayScale.gray55, }, ...common, }; @@ -23,6 +24,7 @@ export const borderDark = { strong: grayScale.gray60, medium: grayScale.gray65, light: grayScale.gray70, + inverted: grayScale.gray30, }, ...common, };