@ -47,7 +47,7 @@ export function RequireOnboarded({
|
||||
}
|
||||
}, [onboardingStatus, navigate]);
|
||||
|
||||
if (onboardingStatus !== OnboardingStatus.Completed) {
|
||||
if (onboardingStatus && onboardingStatus !== OnboardingStatus.Completed) {
|
||||
return (
|
||||
<EmptyContainer>
|
||||
<FadeInStyle>
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ export function CompanyBoardCard() {
|
||||
[updatePipelineProgress],
|
||||
);
|
||||
|
||||
const handleCheckboxChange = () => {
|
||||
setSelected(!selected);
|
||||
const handleCheckboxChange = (checked: boolean) => {
|
||||
setSelected(checked);
|
||||
};
|
||||
|
||||
if (!company || !pipelineProgress) {
|
||||
|
||||
@ -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<HTMLInputElement>(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 (
|
||||
<StyledContainer onClick={onChange}>
|
||||
<input
|
||||
ref={ref}
|
||||
<StyledInputContainer>
|
||||
<StyledInput
|
||||
type="checkbox"
|
||||
name="styled-checkbox"
|
||||
data-testid="input-checkbox"
|
||||
checked={checked}
|
||||
checked={isInternalChecked}
|
||||
indeterminate={indeterminate}
|
||||
onChange={(event) => handleChange(event.target.checked)}
|
||||
/>
|
||||
{checked && <IconCheck />}
|
||||
</StyledContainer>
|
||||
<label htmlFor="checkbox">
|
||||
{indeterminate ? (
|
||||
<IconMinus />
|
||||
) : isInternalChecked ? (
|
||||
<IconCheck />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</label>
|
||||
</StyledInputContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
<StyledContainer>
|
||||
<Checkbox checked={currentRowSelected} onChange={handleContainerClick} />
|
||||
<Checkbox checked={currentRowSelected} onChange={onChange} />
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
<StyledContainer>
|
||||
<Checkbox
|
||||
checked={checked}
|
||||
onChange={handleContainerClick}
|
||||
onChange={onChange}
|
||||
indeterminate={indeterminate}
|
||||
/>
|
||||
</StyledContainer>
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user