Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pano): add posts by site page #681

Merged
merged 4 commits into from
Aug 18, 2023
Merged
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
9 changes: 8 additions & 1 deletion apps/gql/schema/resolvers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const resolvers = {

Query: {
// @see Viewer field resolvers
viewer: () => ({ actor: null, panoFeed: null }),
viewer: () => ({ actor: null, panoFeed: null, panoFeedBySite: null }),
// @see SozlukQuery field resolvers
sozluk: () => ({ term: null, terms: null }),
// @see PanoQuery field resolvers
Expand Down Expand Up @@ -102,6 +102,13 @@ export const resolvers = {
new ConnectionKey(null, parseConnectionArgs(args), { orderBy: { createdAt: "desc" } })
);

return transformPanoPostConnection(posts);
},
panoFeedBySite: async (_, args, { loaders }) => {
const posts = await loaders.pano.post.bySite.load(
new ConnectionKey(args.site, parseConnectionArgs(args), { orderBy: { createdAt: "desc" } })
);

return transformPanoPostConnection(posts);
},
},
Expand Down
1 change: 1 addition & 0 deletions apps/gql/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type Viewer {
last: Int
filter: PanoPostFilter
): PanoPostConnection
panoFeedBySite(site: String!, after: String, first: Int): PanoPostConnection
}

type User implements Node & Actor {
Expand Down
13 changes: 13 additions & 0 deletions apps/gql/schema/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ export type Viewer = {
__typename?: "Viewer";
actor: Maybe<Actor>;
panoFeed: Maybe<PanoPostConnection>;
panoFeedBySite: Maybe<PanoPostConnection>;
};

export type ViewerPanoFeedArgs = {
Expand All @@ -398,6 +399,12 @@ export type ViewerPanoFeedArgs = {
last: InputMaybe<Scalars["Int"]["input"]>;
};

export type ViewerPanoFeedBySiteArgs = {
after: InputMaybe<Scalars["String"]["input"]>;
first: InputMaybe<Scalars["Int"]["input"]>;
site: Scalars["String"]["input"];
};

export type WithIndex<TObject> = TObject & Record<string, any>;
export type ResolversObject<TObject> = WithIndex<TObject>;

Expand Down Expand Up @@ -1088,6 +1095,12 @@ export type ViewerResolvers<
ContextType,
Partial<ViewerPanoFeedArgs>
>;
panoFeedBySite: Resolver<
Maybe<ResolversTypes["PanoPostConnection"]>,
ParentType,
ContextType,
RequireFields<ViewerPanoFeedBySiteArgs, "site">
>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
}>;

Expand Down
2 changes: 1 addition & 1 deletion apps/kampus/app/pano/features/post-list/PostItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const PostItem = (props: PostItemProps) => {
</Link>

<div className="text-muted-foreground flex items-center gap-1 text-sm">
<Link className="text-sm" href={post.url ?? ""}>
<Link className="text-sm" href={post.site ? "pano/site/" + post.site : ""}>
{post.site ?? ""}
</Link>
<ExternalLinkIcon size={12} />
Expand Down
83 changes: 83 additions & 0 deletions apps/kampus/app/pano/site/[...site]/PanoFeedBySite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Suspense } from "react";
import { graphql, useFragment, usePaginationFragment } from "react-relay";

import { Button } from "@kampus/ui";

import { PostItem } from "~/app/pano/features/post-list/PostItem";
import { type PanoFeedBySite_viewer$key } from "./__generated__/PanoFeedBySite_viewer.graphql";
import { type PanoFeedBySiteFragment$key } from "./__generated__/PanoFeedBySiteFragment.graphql";

const fragment = graphql`
fragment PanoFeedBySiteFragment on Viewer
@argumentDefinitions(
site: { type: "String!" }
after: { type: "String" }
first: { type: "Int", defaultValue: 10 }
)
@refetchable(queryName: "PanoFeedBySitePaginationQuery") {
panoFeedBySite(after: $after, first: $first, site: $site)
@connection(key: "PanoFeedBySiteFragment__panoFeedBySite") {
__id
edges {
cursor
node {
id
...PostItem_post
}
}
}
}
`;

const viewerFragment = graphql`
fragment PanoFeedBySite_viewer on Viewer {
...PostItem_viewer
}
`;

interface Props {
panoFeedBySite: PanoFeedBySiteFragment$key;
panoViewerBySite: PanoFeedBySite_viewer$key;
}

export function PanoFeedBySite(props: Props) {
const { data, hasNext, hasPrevious, loadNext, loadPrevious } = usePaginationFragment(
fragment,
props.panoFeedBySite
);
const viewer = useFragment(viewerFragment, props.panoViewerBySite);

const feed = data.panoFeedBySite;

return (
<>
<Suspense fallback="loading">
<section className="flex flex-col gap-4">
{feed?.edges?.map((edge) => {
if (!edge?.node) {
return null;
}

return (
<PostItem
key={edge.node.id}
post={edge.node}
viewerRef={viewer}
postConnectionId={data.panoFeedBySite?.__id}
/>
);
})}

<div className="flex gap-2">
<Button variant="secondary" onClick={() => loadPrevious(10)} disabled={!hasPrevious}>
{"< Prev"}
</Button>
<Button variant="secondary" onClick={() => loadNext(10)} disabled={!hasNext}>
{"Next >"}
</Button>
</div>
</section>
</Suspense>
</>
);
}
33 changes: 33 additions & 0 deletions apps/kampus/app/pano/site/[...site]/PostListBySiteContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client";

import { graphql, usePreloadedQuery } from "react-relay";

import { type SerializablePreloadedQuery } from "@kampus/relay";
import useSerializablePreloadedQuery from "@kampus/relay/use-serializable-preloaded-query";

import { type PostListBySiteContainerQuery } from "./__generated__/PostListBySiteContainerQuery.graphql";
import { PanoFeedBySite } from "./PanoFeedBySite";

interface Props {
preloadedQuery: SerializablePreloadedQuery<PostListBySiteContainerQuery>;
}

const query = graphql`
query PostListBySiteContainerQuery($site: String!) {
viewer {
...PanoFeedBySiteFragment @arguments(site: $site)
...PanoFeedBySite_viewer
}
}
`;

export const PostListBySiteContainer = (props: Props) => {
const queryRef = useSerializablePreloadedQuery(props.preloadedQuery);
const data = usePreloadedQuery(query, queryRef);

if (!data.viewer) {
return null;
}

return <PanoFeedBySite panoFeedBySite={data.viewer} panoViewerBySite={data.viewer} />;
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading