Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion packages/shared/src/components/Feed.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,32 @@
max-width: calc(20rem * var(--num-cards) + var(--feed-gap) * (var(--num-cards) - 1));
}
}
.containerV2 {
max-width: 100%;

@screen desktopL {
max-width: calc(21.25rem * var(--num-cards) + var(--feed-gap) * (var(--num-cards) - 1));
}
}
.cards {
@screen mobileL {
max-width: calc(20rem * var(--num-cards) + var(--feed-gap) * (var(--num-cards) - 1));
}
}
.cardsV2 {
max-width: 100%;

@screen desktopL {
max-width: calc(21.25rem * var(--num-cards) + var(--feed-gap) * (var(--num-cards) - 1));
}
}

.feedRow {
padding-bottom: var(--feed-gap);
}

.cards .feedRow {
.cards .feedRow,
.cardsV2 .feedRow {
grid-template-columns: repeat(var(--num-cards), 1fr);
grid-gap: var(--feed-gap);

Expand Down
11 changes: 10 additions & 1 deletion packages/shared/src/components/Feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { PostItem, UseFeedOptionalParams } from '../hooks/useFeed';
import useFeed, { isBoostedPostAd } from '../hooks/useFeed';
import type { Post } from '../graphql/posts';
import { PostType } from '../graphql/posts';
import type { Spaciness } from '../graphql/settings';
import AuthContext from '../contexts/AuthContext';
import FeedContext from '../contexts/FeedContext';
import SettingsContext from '../contexts/SettingsContext';
Expand Down Expand Up @@ -59,6 +60,7 @@ import { FeedCardContext } from '../features/posts/FeedCardContext';
import {
briefCardFeedFeature,
briefFeedEntrypointPage,
featureFeedLayoutV2,
} from '../lib/featureManagement';
import type { AwardProps } from '../graphql/njord';
import { getProductsQueryOptions } from '../graphql/njord';
Expand Down Expand Up @@ -188,8 +190,15 @@ export default function Feed<T>({
const { user } = useContext(AuthContext);
const { isFallback, query: routerQuery } = useRouter();
const { openNewTab, spaciness, loadedSettings } = useContext(SettingsContext);
const { value: isFeedLayoutV2 } = useConditionalFeature({
feature: featureFeedLayoutV2,
shouldEvaluate: true,
});
const { isListMode } = useFeedLayout();
const numCards = currentSettings.numCards[spaciness ?? 'eco'];
const effectiveSpaciness: Spaciness = isFeedLayoutV2
? 'eco'
: spaciness ?? 'eco';
const numCards = currentSettings.numCards[effectiveSpaciness];
const isSquadFeed = feedName === OtherFeedPage.Squad;
const { shouldUseListFeedLayout } = useFeedLayout();
const trackedFeedFinish = useRef(false);
Expand Down
34 changes: 28 additions & 6 deletions packages/shared/src/components/feeds/FeedContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import FeedContext from '../../contexts/FeedContext';
import styles from '../Feed.module.css';
import type { FeedPagesWithMobileLayoutType } from '../../hooks';
import {
useConditionalFeature,
useFeedLayout,
ToastSubject,
useToastNotification,
Expand All @@ -16,6 +17,7 @@ import {
useFeeds,
useBoot,
} from '../../hooks';
import { featureFeedLayoutV2 } from '../../lib/featureManagement';
import ConditionalWrapper from '../ConditionalWrapper';
import { useActiveFeedNameContext } from '../../contexts';
import { SharedFeedPage } from '../utilities';
Expand Down Expand Up @@ -69,24 +71,34 @@ const cardListClass = {
export const getFeedGapPx = {
'gap-2': 8,
'gap-3': 12,
'gap-4': 16,
'gap-5': 20,
'gap-8': 32,
'gap-12': 48,
'gap-14': 56,
};

/**
* Returns the appropriate gap class based on layout mode and spaciness.
* @param defaultGridGap - Optional override for grid gap (used by feature flags like feed_layout_v2)
*/
export const gapClass = ({
isList,
isFeedLayoutList,
space,
defaultGridGap,
}: {
isList: boolean;
isFeedLayoutList: boolean;
space: Spaciness;
defaultGridGap?: string;
}): string => {
if (isFeedLayoutList) {
return '';
}
if (defaultGridGap) {
return defaultGridGap;
}
return isList ? listGaps[space] ?? 'gap-2' : gridGaps[space] ?? 'gap-8';
};

Expand Down Expand Up @@ -150,31 +162,40 @@ export const FeedContainer = ({
const currentSettings = useContext(FeedContext);
const { subject } = useToastNotification();
const { spaciness, loadedSettings } = useContext(SettingsContext);
const { value: isFeedLayoutV2 } = useConditionalFeature({
feature: featureFeedLayoutV2,
shouldEvaluate: true,
});
const { shouldUseListFeedLayout, isListMode } = useFeedLayout();
const isLaptop = useViewSize(ViewSize.Laptop);
const { feedName } = useActiveFeedNameContext();
const { isAnyExplore, isExplorePopular, isExploreLatest } = useFeedName({
feedName,
});
const router = useRouter();
const numCards = currentSettings.numCards[spaciness ?? 'eco'];
const effectiveSpaciness: Spaciness = isFeedLayoutV2
? 'eco'
: spaciness ?? 'eco';
const numCards = currentSettings.numCards[effectiveSpaciness];
const isList =
(isHorizontal || isListMode) && !shouldUseListFeedLayout
? false
: (isListMode && numCards > 1) || shouldUseListFeedLayout;
const v2GridGap = isFeedLayoutV2 ? 'gap-4' : undefined;
const feedGapPx =
getFeedGapPx[
gapClass({
isList,
isFeedLayoutList: shouldUseListFeedLayout,
space: spaciness,
space: effectiveSpaciness,
defaultGridGap: v2GridGap,
})
];
const style = {
'--num-cards': isHorizontal && isListMode && numCards >= 2 ? 2 : numCards,
'--feed-gap': `${feedGapPx / 16}rem`,
} as CSSProperties;
const cardContainerStyle = { ...getStyle(isList, spaciness) };
const cardContainerStyle = { ...getStyle(isList, effectiveSpaciness) };
const isFinder = router.pathname === '/search/posts';
const isSearch = showSearch && !isFinder;

Expand Down Expand Up @@ -222,7 +243,7 @@ export const FeedContainer = ({
<div
className={classNames(
'relative flex w-full flex-col laptopL:mx-auto',
styles.container,
isFeedLayoutV2 ? styles.containerV2 : styles.container,
className,
)}
>
Expand Down Expand Up @@ -264,7 +285,7 @@ export const FeedContainer = ({
className={classNames(
'relative mx-auto w-full',
styles.feed,
!isList && styles.cards,
!isList && (isFeedLayoutV2 ? styles.cardsV2 : styles.cards),
)}
style={cardContainerStyle}
aria-live={subject === ToastSubject.Feed ? 'assertive' : 'off'}
Expand Down Expand Up @@ -322,7 +343,8 @@ export const FeedContainer = ({
gapClass({
isList,
isFeedLayoutList: shouldUseListFeedLayout,
space: spaciness,
space: effectiveSpaciness,
defaultGridGap: v2GridGap,
}),
cardClass({ isList, numberOfCards: numCards, isHorizontal }),
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import classNames from 'classnames';
import { PageWidgets } from '../../utilities';
import type { SearchSuggestion } from '../../../graphql/search';
import { SearchProviderEnum } from '../../../graphql/search';
import type { Spaciness } from '../../../graphql/settings';
import { useSearchResultsLayout } from '../../../hooks/search/useSearchResultsLayout';
import { LogEvent, Origin, TargetType } from '../../../lib/log';
import { useLogContext } from '../../../contexts/LogContext';
Expand All @@ -14,10 +15,11 @@ import { SearchResultsSources } from './SearchResultsSources';
import { useSearchProviderSuggestions } from '../../../hooks/search';
import SettingsContext from '../../../contexts/SettingsContext';
import { gapClass } from '../../feeds/FeedContainer';
import { useFeedLayout } from '../../../hooks';
import { useConditionalFeature, useFeedLayout } from '../../../hooks';
import { SearchResultsUsers } from './SearchResultsUsers';
import SearchFilterTimeButton from '../SearchFilterTimeButton';
import SearchFilterPostTypeButton from '../SearchFilterPostTypeButton';
import { featureFeedLayoutV2 } from '../../../lib/featureManagement';

type SearchResultsLayoutProps = PropsWithChildren;

Expand All @@ -27,6 +29,12 @@ export const SearchResultsLayout = (
const { children } = props;
const { isListMode } = useFeedLayout();
const { spaciness } = useContext(SettingsContext);
const { value: isFeedLayoutV2 } = useConditionalFeature({
feature: featureFeedLayoutV2,
shouldEvaluate: true,
});
const effectiveSpaciness: Spaciness = isFeedLayoutV2 ? 'eco' : spaciness;
const v2GridGap = isFeedLayoutV2 ? 'gap-4' : undefined;
const { isSearchPageLaptop } = useSearchResultsLayout();

const {
Expand Down Expand Up @@ -103,7 +111,8 @@ export const SearchResultsLayout = (
gapClass({
isList: true,
isFeedLayoutList: false,
space: spaciness,
space: effectiveSpaciness,
defaultGridGap: v2GridGap,
}),
isListMode
? `flex flex-col`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export const InviteMemberModal = ({
const [isCopying, copyLink] = useCopyLink();
const { openModal } = useLazyModal();

const { organization, referralUrl, seats } = useOrganization(organizationId);
const { organization, referralUrl, seats } = useOrganization(organizationId, {
includeMembers: true,
});

const isMobile = useViewSize(ViewSize.MobileL);

Expand Down
77 changes: 59 additions & 18 deletions packages/shared/src/features/organizations/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,72 @@ export const ORGANIZATION_SHORT_FRAGMENT = gql`
}
`;

export const ORGANIZATION_FRAGMENT = gql`
fragment OrganizationFragment on Organization {
export const ORGANIZATION_BASE_FRAGMENT = gql`
fragment OrganizationBaseFragment on Organization {
...OrganizationShortFragment
seats
activeSeats
status
}

${ORGANIZATION_SHORT_FRAGMENT}
`;

export const ORGANIZATION_FRAGMENT = gql`
fragment OrganizationFragment on Organization {
...OrganizationBaseFragment
members {
...OrganizationMemberFragment
}
}

${ORGANIZATION_SHORT_FRAGMENT}
${ORGANIZATION_BASE_FRAGMENT}
${ORGANIZATION_MEMBER_FRAGMENT}
`;

export const USER_ORGANIZATION_FRAGMENT = gql`
fragment UserOrganizationFragment on UserOrganization {
export const USER_ORGANIZATION_BASE_FRAGMENT = gql`
fragment UserOrganizationBaseFragment on UserOrganization {
role
referralToken
referralUrl
seatType
}
`;

export const USER_ORGANIZATION_FRAGMENT = gql`
fragment UserOrganizationFragment on UserOrganization {
...UserOrganizationBaseFragment
referralUrl
}

${USER_ORGANIZATION_BASE_FRAGMENT}
`;

export const ORGANIZATIONS_BASE_QUERY = gql`
query OrganizationsBase {
organizations {
...UserOrganizationBaseFragment
organization {
...OrganizationShortFragment
}
}
}
${USER_ORGANIZATION_BASE_FRAGMENT}
${ORGANIZATION_SHORT_FRAGMENT}
`;

export const ORGANIZATION_BASE_QUERY = gql`
query OrganizationBase($id: ID!) {
organization(id: $id) {
...UserOrganizationBaseFragment
organization {
...OrganizationBaseFragment
}
}
}
${USER_ORGANIZATION_BASE_FRAGMENT}
${ORGANIZATION_BASE_FRAGMENT}
`;

export const ORGANIZATIONS_QUERY = gql`
query Organizations {
organizations {
Expand Down Expand Up @@ -98,27 +139,27 @@ export const GET_ORGANIZATION_BY_ID_AND_INVITE_TOKEN_QUERY = gql`
export const UPDATE_ORGANIZATION_MUTATION = gql`
mutation UpdateOrganization($id: ID!, $name: String, $image: Upload) {
updateOrganization(id: $id, name: $name, image: $image) {
...UserOrganizationFragment
...UserOrganizationBaseFragment
organization {
...OrganizationFragment
...OrganizationBaseFragment
}
}
}
${USER_ORGANIZATION_FRAGMENT}
${ORGANIZATION_FRAGMENT}
${USER_ORGANIZATION_BASE_FRAGMENT}
${ORGANIZATION_BASE_FRAGMENT}
`;

export const JOIN_ORGANIZATION_MUTATION = gql`
mutation JoinOrganization($id: ID!, $token: String!) {
joinOrganization(id: $id, token: $token) {
...UserOrganizationFragment
...UserOrganizationBaseFragment
organization {
...OrganizationFragment
...OrganizationBaseFragment
}
}
}
${USER_ORGANIZATION_FRAGMENT}
${ORGANIZATION_FRAGMENT}
${USER_ORGANIZATION_BASE_FRAGMENT}
${ORGANIZATION_BASE_FRAGMENT}
`;

export const LEAVE_ORGANIZATION_MUTATION = gql`
Expand All @@ -132,14 +173,14 @@ export const LEAVE_ORGANIZATION_MUTATION = gql`
export const UPDATE_ORGANIZATION_SUBSCRIPTION_MUTATION = gql`
mutation UpdateOrganizationSubscription($id: ID!, $quantity: Int!) {
updateOrganizationSubscription(id: $id, quantity: $quantity) {
...UserOrganizationFragment
...UserOrganizationBaseFragment
organization {
...OrganizationFragment
...OrganizationBaseFragment
}
}
}
${USER_ORGANIZATION_FRAGMENT}
${ORGANIZATION_FRAGMENT}
${USER_ORGANIZATION_BASE_FRAGMENT}
${ORGANIZATION_BASE_FRAGMENT}
`;

export const PREVIEW_SUBSCRIPTION_UPDATE_QUERY = gql`
Expand Down
Loading