diff --git a/front/src/modules/activities/timeline/components/Timeline.tsx b/front/src/modules/activities/timeline/components/Timeline.tsx index 62efcf24c..42471a828 100644 --- a/front/src/modules/activities/timeline/components/Timeline.tsx +++ b/front/src/modules/activities/timeline/components/Timeline.tsx @@ -35,11 +35,11 @@ const StyledTimelineContainer = styled.div` display: flex; flex: 1 0 0; flex-direction: column; - gap: 4px; + gap: ${({ theme }) => theme.spacing(1)}; justify-content: flex-start; - overflow-y: auto; + overflow-y: ${() => (useIsMobile() ? 'none' : 'auto')}; - padding: 12px 16px 12px 16px; + padding: ${({ theme }) => theme.spacing(3)} ${({ theme }) => theme.spacing(4)}; `; const StyledTimelineEmptyContainer = styled.div` @@ -48,7 +48,7 @@ const StyledTimelineEmptyContainer = styled.div` display: flex; flex: 1 0 0; flex-direction: column; - gap: 8px; + gap: ${({ theme }) => theme.spacing(2)}; justify-content: center; `; @@ -81,7 +81,7 @@ const StyledTopActionBar = styled.div` flex-direction: column; left: 0px; padding: 12px 16px 12px 16px; - position: sticky; + position: ${() => (useIsMobile() ? 'relative' : 'sticky')}; top: 0px; `; diff --git a/front/src/modules/activities/timeline/components/TimelineActivity.tsx b/front/src/modules/activities/timeline/components/TimelineActivity.tsx index a92637347..112f141a6 100644 --- a/front/src/modules/activities/timeline/components/TimelineActivity.tsx +++ b/front/src/modules/activities/timeline/components/TimelineActivity.tsx @@ -5,6 +5,7 @@ import { useCompleteTask } from '@/activities/hooks/useCompleteTask'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { IconNotes } from '@/ui/icon'; import { OverflowingTextWithTooltip } from '@/ui/tooltip/OverflowingTextWithTooltip'; +import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { Activity, User } from '~/generated/graphql'; import { beautifyExactDateTime, @@ -65,7 +66,9 @@ const StyledCardContainer = styled.div` display: flex; flex-direction: column; gap: ${({ theme }) => theme.spacing(2)}; + max-width: 100%; padding: 4px 0px 20px 0px; + width: ${() => (useIsMobile() ? '100%' : '400px')}; `; const StyledCard = styled.div` @@ -76,9 +79,7 @@ const StyledCard = styled.div` display: flex; flex-direction: column; gap: ${({ theme }) => theme.spacing(3)}; - max-width: 100%; - position: relative; - width: 400px; + width: calc(100% - ${({ theme }) => theme.spacing(4)}); `; const StyledCardContent = styled.div` @@ -105,14 +106,14 @@ const StyledTooltip = styled(Tooltip)` const StyledCardDetailsContainer = styled.div` padding: ${({ theme }) => theme.spacing(2)}; - width: 100%; + width: calc(100% - ${({ theme }) => theme.spacing(4)}); `; const StyledTimelineItemContainer = styled.div` align-items: center; align-self: stretch; display: flex; - gap: 16px; + gap: ${({ theme }) => theme.spacing(4)}; `; type OwnProps = { diff --git a/front/src/modules/companies/components/AddPersonToCompany.tsx b/front/src/modules/companies/components/AddPersonToCompany.tsx new file mode 100644 index 000000000..faac52272 --- /dev/null +++ b/front/src/modules/companies/components/AddPersonToCompany.tsx @@ -0,0 +1,102 @@ +import { useState } from 'react'; +import { getOperationName } from '@apollo/client/utilities'; +import styled from '@emotion/styled'; +import { flip, offset, useFloating } from '@floating-ui/react'; +import { IconPlus } from '@tabler/icons-react'; + +import { + PeoplePicker, + PersonForSelect, +} from '@/people/components/PeoplePicker'; +import { GET_PEOPLE } from '@/people/graphql/queries/getPeople'; +import { ButtonSize } from '@/ui/button/components/Button'; +import { IconButton } from '@/ui/button/components/IconButton'; +import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope'; +import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; +import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; +import { useUpdateOnePersonMutation } from '~/generated/graphql'; + +const StyledContainer = styled.div` + position: relative; +`; + +export function AddPersonToCompany({ + companyId, + peopleIds, +}: { + companyId: string; + peopleIds?: string[]; +}) { + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const [updatePerson] = useUpdateOnePersonMutation(); + const { refs, floatingStyles } = useFloating({ + placement: 'right-start', + middleware: [flip(), offset({ mainAxis: -20, crossAxis: 25 })], + }); + + const { + setHotkeyScopeAndMemorizePreviousScope, + goBackToPreviousHotkeyScope, + } = usePreviousHotkeyScope(); + + function handlePersonSelected(companyId: string) { + return async (newPerson: PersonForSelect | null) => { + if (newPerson) { + await updatePerson({ + variables: { + where: { + id: newPerson.id, + }, + data: { + company: { connect: { id: companyId } }, + }, + }, + refetchQueries: [getOperationName(GET_PEOPLE) ?? ''], + }); + handleClosePicker(); + } + }; + } + + function handleClosePicker() { + if (isDropdownOpen) { + setIsDropdownOpen(false); + goBackToPreviousHotkeyScope(); + } + } + + function handleOpenPicker() { + if (!isDropdownOpen) { + setIsDropdownOpen(true); + setHotkeyScopeAndMemorizePreviousScope( + RelationPickerHotkeyScope.RelationPicker, + ); + } + } + + return ( + + +
+ } + onClick={handleOpenPicker} + size={ButtonSize.Small} + variant={'transparent'} + /> +
+ + {isDropdownOpen && ( +
+ +
+ )} +
+
+ ); +} diff --git a/front/src/modules/companies/components/CompanyTeam.tsx b/front/src/modules/companies/components/CompanyTeam.tsx index ded54eddd..2e85f79fb 100644 --- a/front/src/modules/companies/components/CompanyTeam.tsx +++ b/front/src/modules/companies/components/CompanyTeam.tsx @@ -3,12 +3,13 @@ import styled from '@emotion/styled'; import { PeopleCard } from '@/people/components/PeopleCard'; import { Company, useGetPeopleQuery } from '~/generated/graphql'; +import { AddPersonToCompany } from './AddPersonToCompany'; + export type CompanyTeamPropsType = { company: Pick; }; const StyledContainer = styled.div` - align-items: flex-start; display: flex; flex-direction: column; gap: ${({ theme }) => theme.spacing(2)}; @@ -17,13 +18,10 @@ const StyledContainer = styled.div` const StyledTitleContainer = styled.div` align-items: center; - backdrop-filter: blur(5px); color: ${({ theme }) => theme.font.color.primary}; display: flex; justify-content: space-between; padding-bottom: ${({ theme }) => theme.spacing(0)}; - padding-left: ${({ theme }) => theme.spacing(3)}; - padding-right: ${({ theme }) => theme.spacing(3)}; padding-top: ${({ theme }) => theme.spacing(3)}; `; @@ -55,12 +53,15 @@ export function CompanyTeam({ company }: CompanyTeamPropsType) { }, }); + const peopleIds = data?.people?.map(({ id }) => id); + return ( <> {Boolean(data?.people?.length) && ( Team + {data?.people?.map((person, id) => ( diff --git a/front/src/modules/people/components/PeopleCard.tsx b/front/src/modules/people/components/PeopleCard.tsx index dd15c5d90..be057c03c 100644 --- a/front/src/modules/people/components/PeopleCard.tsx +++ b/front/src/modules/people/components/PeopleCard.tsx @@ -61,7 +61,7 @@ const StyledTitle = styled.div` const StyledJobTitle = styled.div` border-radius: ${({ theme }) => theme.spacing(1)}; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${({ theme }) => theme.font.color.tertiary}; padding-bottom: ${({ theme }) => theme.spacing(0.5)}; padding-left: ${({ theme }) => theme.spacing(0)}; padding-right: ${({ theme }) => theme.spacing(2)}; diff --git a/front/src/modules/people/components/PeoplePicker.tsx b/front/src/modules/people/components/PeoplePicker.tsx index 06783b7ec..359e45cae 100644 --- a/front/src/modules/people/components/PeoplePicker.tsx +++ b/front/src/modules/people/components/PeoplePicker.tsx @@ -10,13 +10,19 @@ export type OwnProps = { personId: string | null; onSubmit: (newPersonId: PersonForSelect | null) => void; onCancel?: () => void; + excludePersonIds?: string[]; }; -type PersonForSelect = EntityForSelect & { +export type PersonForSelect = EntityForSelect & { entityType: Entity.Person; }; -export function PeoplePicker({ personId, onSubmit, onCancel }: OwnProps) { +export function PeoplePicker({ + personId, + onSubmit, + onCancel, + excludePersonIds, +}: OwnProps) { const [searchFilter] = useRecoilScopedState( relationPickerSearchFilterScopedState, ); @@ -34,6 +40,7 @@ export function PeoplePicker({ personId, onSubmit, onCancel }: OwnProps) { }), orderByField: 'firstName', searchOnFields: ['firstName', 'lastName'], + excludePersonIds, }); async function handleEntitySelected( diff --git a/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts b/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts index e10b335ca..6b71d1a22 100644 --- a/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts +++ b/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts @@ -60,6 +60,7 @@ export function useFilteredSearchEntityQuery< mappingFunction, limit, searchFilter, // TODO: put in a scoped recoil state + excludePersonIds = [], }: { queryHook: ( queryOptions?: Apollo.QueryHookOptions< @@ -74,6 +75,7 @@ export function useFilteredSearchEntityQuery< mappingFunction: (entity: EntityType) => CustomEntityForSelect; limit?: number; searchFilter: string; + excludePersonIds?: string[]; }): EntitiesForMultipleEntitySelect { const { loading: selectedEntitiesLoading, data: selectedEntitiesData } = queryHook({ @@ -129,7 +131,7 @@ export function useFilteredSearchEntityQuery< }, { id: { - notIn: selectedIds, + notIn: [...selectedIds, ...excludePersonIds], }, }, ], diff --git a/front/src/modules/ui/layout/components/ShowPageContainer.tsx b/front/src/modules/ui/layout/components/ShowPageContainer.tsx index 608dc80be..bd6bd50c1 100644 --- a/front/src/modules/ui/layout/components/ShowPageContainer.tsx +++ b/front/src/modules/ui/layout/components/ShowPageContainer.tsx @@ -6,6 +6,7 @@ export const ShowPageContainer = styled.div` display: flex; flex-direction: ${() => (useIsMobile() ? 'column' : 'row')}; gap: ${({ theme }) => (useIsMobile() ? theme.spacing(3) : '0')}; - height: 100%; + height: ${() => (useIsMobile() ? '100%' : 'auto')}; + overflow-x: ${() => (useIsMobile() ? 'hidden' : 'auto')}; width: ${() => (useIsMobile() ? `calc(100% - 2px);` : '100%')}; `; diff --git a/front/src/modules/ui/layout/show-page/components/ShowPageLeftContainer.tsx b/front/src/modules/ui/layout/show-page/components/ShowPageLeftContainer.tsx index 762392f0c..5824ba086 100644 --- a/front/src/modules/ui/layout/show-page/components/ShowPageLeftContainer.tsx +++ b/front/src/modules/ui/layout/show-page/components/ShowPageLeftContainer.tsx @@ -14,11 +14,12 @@ export const ShowPageLeftContainer = styled.div` display: flex; flex-direction: column; gap: ${({ theme }) => theme.spacing(3)}; - overflow-y: scroll; padding: 0px ${({ theme }) => theme.spacing(3)}; width: ${({ theme }) => { const isMobile = useIsMobile(); return isMobile ? `calc(100% - ${theme.spacing(6)})` : '320px'; }}; + + z-index: 10; `; diff --git a/front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx b/front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx index a65b8c4ee..0a2f203c6 100644 --- a/front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx +++ b/front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx @@ -1,9 +1,16 @@ import styled from '@emotion/styled'; +import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; + export const ShowPageRightContainer = styled.div` display: flex; flex: 1 0 0; flex-direction: column; justify-content: center; - overflow: hidden; + overflow: ${() => (useIsMobile() ? 'none' : 'hidden')}; + width: ${({ theme }) => { + const isMobile = useIsMobile(); + + return isMobile ? `calc(100% - ${theme.spacing(6)})` : 'auto'; + }}; `; diff --git a/front/src/modules/ui/utilities/hotkey/hooks/usePreviousHotkeyScope.ts b/front/src/modules/ui/utilities/hotkey/hooks/usePreviousHotkeyScope.ts index 09f648b24..b4df92490 100644 --- a/front/src/modules/ui/utilities/hotkey/hooks/usePreviousHotkeyScope.ts +++ b/front/src/modules/ui/utilities/hotkey/hooks/usePreviousHotkeyScope.ts @@ -30,7 +30,6 @@ export function usePreviousHotkeyScope() { .valueOrThrow(); setHotkeyScope(scope, customScopes); - setPreviousHotkeyScope(currentHotkeyScope); }, [setPreviousHotkeyScope], diff --git a/front/src/modules/ui/utilities/hotkey/hooks/useSetHotkeyScope.ts b/front/src/modules/ui/utilities/hotkey/hooks/useSetHotkeyScope.ts index 81b6e28ba..9e53c7752 100644 --- a/front/src/modules/ui/utilities/hotkey/hooks/useSetHotkeyScope.ts +++ b/front/src/modules/ui/utilities/hotkey/hooks/useSetHotkeyScope.ts @@ -26,7 +26,6 @@ export function useSetHotkeyScope() { const currentHotkeyScope = await snapshot.getPromise( currentHotkeyScopeState, ); - if (currentHotkeyScope.scope === hotkeyScopeToSet) { if (!isDefined(customScopes)) { if ( @@ -68,8 +67,8 @@ export function useSetHotkeyScope() { } scopesToSet.push(newHotkeyScope.scope); - set(internalHotkeysEnabledScopesState, scopesToSet); + set(currentHotkeyScopeState, newHotkeyScope); }, [], );