Skip to content

Commit

Permalink
Added waves details page
Browse files Browse the repository at this point in the history
  • Loading branch information
dkildar committed Nov 20, 2024
1 parent 5c3d3d2 commit e6cb193
Show file tree
Hide file tree
Showing 17 changed files with 214 additions and 98 deletions.
18 changes: 5 additions & 13 deletions src/api/queries/get-discussions-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Entry } from "@/entities";
import { bridgeApiCall } from "@/api/bridge";
import { parseAsset } from "@/utils";
import { SortOrder } from "@/enums";
import { IdentifiableEntry } from "@/app/decks/_components/columns/deck-threads-manager";
import { QueryClient } from "@tanstack/react-query";

export function sortDiscussions(entry: Entry, discussion: Entry[], order: SortOrder) {
Expand Down Expand Up @@ -102,13 +101,10 @@ export const getDiscussionsMapQuery = (entry: Entry | undefined, enabled: boolea
EcencyQueriesManager.generateClientServerQuery({
queryKey: [QueryIdentifiers.FETCH_DISCUSSIONS_MAP, entry?.author, entry?.permlink],
queryFn: async () => {
const response = await bridgeApiCall<Record<string, IdentifiableEntry> | null>(
"get_discussion",
{
author: entry!!.author,
permlink: entry!!.permlink
}
);
const response = await bridgeApiCall<Record<string, Entry> | null>("get_discussion", {
author: entry!!.author,
permlink: entry!!.permlink
});
if (response) {
return response;
}
Expand All @@ -118,11 +114,7 @@ export const getDiscussionsMapQuery = (entry: Entry | undefined, enabled: boolea
refetchOnMount: true
});

export function addReplyToDiscussionsList(
entry: IdentifiableEntry,
reply: Entry,
queryClient: QueryClient
) {
export function addReplyToDiscussionsList(entry: Entry, reply: Entry, queryClient: QueryClient) {
queryClient.setQueryData<Record<string, Entry | null>>(
[QueryIdentifiers.FETCH_DISCUSSIONS_MAP, entry?.author, entry?.permlink],
(data) => {
Expand Down
1 change: 1 addition & 0 deletions src/api/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ export * from "./get-chain-properties-query";
export * from "./get-gifs-query";
export * from "./spk";
export * from "./waves";
export * from "./get-discussions-query";
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useRef } from "react";
import React, { useRef } from "react";
import { DeckThreadItemSkeleton, ThreadItem } from "../deck-items";
import { IdentifiableEntry } from "../deck-threads-manager";
import { DeckThreadsForm } from "../../deck-threads-form";
Expand All @@ -8,13 +8,11 @@ import { Button } from "@ui/button";
import { EcencyEntriesCacheManagement } from "@/core/caches";
import i18next from "i18next";
import { arrowLeftSvg } from "@ui/svg";
import {
addReplyToDiscussionsList,
getDiscussionsMapQuery
} from "@/api/queries/get-discussions-query";
import { addReplyToDiscussionsList } from "@/api/queries/get-discussions-query";
import { useMounted } from "@/utils/use-mounted";
import { useQueryClient } from "@tanstack/react-query";
import { WaveEntry } from "@/entities";
import { useWaveDiscussionsList } from "@/features/waves";

interface Props {
entry: WaveEntry;
Expand All @@ -33,59 +31,13 @@ export const DeckThreadItemViewer = ({
const queryClient = useQueryClient();

const { data: entry } =
EcencyEntriesCacheManagement.getEntryQuery<IdentifiableEntry>(initialEntry).useClientQuery();
EcencyEntriesCacheManagement.getEntryQuery<WaveEntry>(initialEntry).useClientQuery();
const isMounted = useMounted();

const { data: discussions } = getDiscussionsMapQuery(entry).useClientQuery();
const { addReply } = EcencyEntriesCacheManagement.useAddReply(entry);
const { updateRepliesCount } = EcencyEntriesCacheManagement.useUpdateRepliesCount(entry);
const { updateEntryQueryData } = EcencyEntriesCacheManagement.useUpdateEntry();

const build = useCallback(
(dataset: Record<string, IdentifiableEntry>) => {
const result: IdentifiableEntry[] = [];
const values = [...Object.values(dataset).filter((v) => v.permlink !== entry?.permlink)];
Object.entries(dataset)
.filter(([_, v]) => v.permlink !== entry?.permlink)
.forEach(([key, value]) => {
const parent = values.find((v) => v.replies.includes(key));
if (parent) {
const existingTempIndex = result.findIndex(
(v) => v.author === parent.author && v.permlink === parent.permlink
);
if (existingTempIndex > -1) {
result[existingTempIndex].replies.push(value);
result[existingTempIndex].replies = result[existingTempIndex].replies.filter(
(r) => r !== key
);
} else {
parent.replies.push(value);
parent.replies = parent.replies.filter((r) => r !== key);
result.push(parent);
}
} else if (
result.every((r) => r.author !== value.author && r.permlink !== value.permlink)
) {
result.push(value);
}
});
return result;
},
[entry?.permlink]
);

const data = useMemo(() => {
const tempResponse = { ...discussions };
Object.values(tempResponse).forEach((i) => {
i.host = entry?.host ?? "";
});

return build(tempResponse);
}, [build, discussions, entry?.host]);

useEffect(() => {
updateEntryQueryData(Array.from(Object.values(discussions ?? {})));
}, [discussions]);
const data = useWaveDiscussionsList(entry!);

return (
<div
Expand Down
2 changes: 2 additions & 0 deletions src/app/waves/[author]/[permlink]/_components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./wave-view-details";
export * from "./wave-view-discussion";
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use client";

import { WavesListItemHeader } from "@/app/waves/_components/waves-list-item-header";
import { renderPostBody } from "@ecency/render-helper";
import { useRenderWaveBody, WaveActions, WaveForm } from "@/features/waves";
import { motion } from "framer-motion";
import { WaveEntry } from "@/entities";
import React, { useRef } from "react";
import useMount from "react-use/lib/useMount";

interface Props {
entry: WaveEntry;
}

export function WaveViewDetails({ entry }: Props) {
const renderAreaRef = useRef<HTMLDivElement>(null);
const renderBody = useRenderWaveBody(renderAreaRef, entry, {});

useMount(() => renderBody());
const status = "default";

return (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="relative rounded-2xl bg-white dark:bg-dark-200 cursor-pointer"
>
<WavesListItemHeader entry={entry} hasParent={false} pure={false} status={status} />
<div
className="p-4 thread-render"
ref={renderAreaRef}
dangerouslySetInnerHTML={{ __html: renderPostBody(entry!) }}
/>
<WaveActions
status={status}
entry={entry}
onEntryView={() => {}}
hasParent={false}
pure={false}
onEdit={() => {}}
/>
<div className="border-t border-[--border-color]"></div>
<WaveForm entry={undefined} replySource={entry} />
</motion.div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import { WaveEntry } from "@/entities";
import { WavesListItem } from "@/app/waves/_components";
import { useWaveDiscussionsList } from "@/features/waves";

interface Props {
entry: WaveEntry;
}

export function WaveViewDiscussion({ entry }: Props) {
const data = useWaveDiscussionsList(entry);

return (
<div>
<div className="p-4 text-sm font-semibold opacity-50">Replies</div>
<div>
{data?.map((item, i) => (
<WavesListItem key={item.post_id} item={item as WaveEntry} i={i} />
))}
</div>
</div>
);
}
32 changes: 23 additions & 9 deletions src/app/waves/[author]/[permlink]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
"use client";

import { WavesListItem } from "@/app/waves/_components";
import { EcencyEntriesCacheManagement } from "@/core/caches";
import { notFound } from "next/navigation";
import { WaveViewDetails, WaveViewDiscussion } from "@/app/waves/[author]/[permlink]/_components";
import { WaveEntry } from "@/entities";
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
import { getQueryClient } from "@/core/react-query";

interface Props {
params: {
params: Promise<{
author: string;
permlink: string;
};
}>;
}

export default function WaveViewPage({ params: { author, permlink } }: Props) {
const { data } = EcencyEntriesCacheManagement.getEntryQueryByPath(
export default async function WaveViewPage({ params }: Props) {
const { author, permlink } = await params;

const data = (await EcencyEntriesCacheManagement.getEntryQueryByPath(
author,
permlink
).useClientQuery();
).prefetch()) as WaveEntry;

if (!data) {
return notFound();
}

return <div>{data && <WavesListItem item={data as WaveEntry} i={0} />}</div>;
return (
<HydrationBoundary state={dehydrate(getQueryClient())}>
<div className="flex flex-col gap-4 lg:gap-6 xl:gap-8">
<WaveViewDetails entry={data} />
<WaveViewDiscussion entry={data} />
</div>
</HydrationBoundary>
);
}
2 changes: 1 addition & 1 deletion src/app/waves/_components/waves-host-selection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function WavesHostSelection({ host, setHost }: Props) {

return (
<div className="absolute top-[64px] md:top-[69px] z-10 left-0 w-full md:p-2">
<div className="max-w-[1600px] mx-auto border-b border-[--border-color] text-sm font-semibold px-4 overflow-x-auto flex items-center justify-around bg-white dark:bg-dark-700 w-full gap-4 rounded-b-2xl">
<div className="max-w-[1600px] mx-auto text-sm font-semibold px-4 overflow-x-auto flex items-center justify-around bg-white dark:bg-dark-200 w-full gap-4 rounded-b-2xl">
{availableHosts.map((item, i) => (
<TabItem
name={item}
Expand Down
27 changes: 24 additions & 3 deletions src/app/waves/_components/waves-list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import { WaveEntry } from "@/entities";
import { WavesListItemHeader } from "@/app/waves/_components/waves-list-item-header";
import { useRef } from "react";
import React, { useCallback, useRef } from "react";
import { useRenderWaveBody, WaveActions } from "@/features/waves";
import useMount from "react-use/lib/useMount";
import { renderPostBody } from "@ecency/render-helper";
import { EcencyEntriesCacheManagement } from "@/core/caches";
import { motion } from "framer-motion";
import "./waves-list-item.scss";
import { useRouter } from "next/navigation";

interface Props {
item: WaveEntry;
Expand All @@ -17,6 +18,8 @@ interface Props {

export function WavesListItem({ item, i }: Props) {
const renderAreaRef = useRef<HTMLDivElement>(null);
const router = useRouter();

const { data: entry } =
EcencyEntriesCacheManagement.getEntryQuery<WaveEntry>(item).useClientQuery();

Expand All @@ -25,12 +28,31 @@ export function WavesListItem({ item, i }: Props) {
useMount(() => renderBody());
const status = "default";

const onClick = useCallback(
(e: React.MouseEvent) => {
const path = `/waves/${item.author}/${item.permlink}`;

switch (e.button) {
case 0:
router.push(path);
break;
case 1:
window.open(path, "_blank");
break;
default:
null;
}
},
[item.author, item.permlink, router]
);

return (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: i * 0.2 }}
className="first:rounded-t-2xl bg-white dark:bg-dark-200 border-b border-[--border-color] cursor-pointer"
className="first:rounded-t-2xl last:rounded-b-2xl bg-white dark:bg-dark-200 border-b border-[--border-color] last:border-b-0 hover:bg-gray-100 dark:hover:bg-dark-600-010 cursor-pointer"
onMouseDown={onClick}
>
<WavesListItemHeader entry={entry!} hasParent={false} pure={false} status={status} />
<div
Expand All @@ -42,7 +64,6 @@ export function WavesListItem({ item, i }: Props) {
status={status}
entry={item}
onEntryView={() => {}}
commentsSlot={<></>}
hasParent={false}
pure={false}
onEdit={() => {}}
Expand Down
22 changes: 15 additions & 7 deletions src/app/waves/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Feedback, Navbar, ScrollToTop } from "@/features/shared";
import { PropsWithChildren, ReactNode, useCallback, useState } from "react";
import { classNameObject } from "@ui/util";
import { useMount, useUnmount } from "react-use";
import { usePathname } from "next/navigation";

interface Props {
view: ReactNode;
Expand All @@ -12,25 +13,32 @@ interface Props {
export default function WavesLayout(props: PropsWithChildren<Props>) {
const [scroll, setScroll] = useState(0);

const handleScroll = useCallback((event: Event) => setScroll(window.scrollY), []);
const pathname = usePathname();
const handleScroll = useCallback(() => setScroll(window.scrollY), []);

useMount(() => window.addEventListener("scroll", handleScroll));
useUnmount(() => window.removeEventListener("scroll", handleScroll));

return (
<div
className={classNameObject({
"bg-blue-duck-egg dark:bg-dark-700 min-h-full": true,
"[&_.ecency-navbar-desktop]:rounded-b-none": scroll <= 32
"bg-blue-duck-egg dark:bg-dark-700 min-h-[100vh]": true,
"[&_.ecency-navbar-desktop]:rounded-b-none": pathname === "/waves" ? scroll <= 32 : false
})}
>
<Feedback />
<ScrollToTop />
<Navbar experimental={true} />
<div className="container pt-[156px] mx-auto grid grid-cols-12">
<div className="col-span-3"></div>
<div className="col-span-6">{props.children}</div>
<div className="col-span-3"></div>
<div
className={classNameObject({
"container mx-auto grid grid-cols-12": true,
"pt-[156px]": pathname === "/waves",
"pt-[96px]": pathname !== "/waves"
})}
>
<div className="col-span-2"></div>
<div className="col-span-8">{props.children}</div>
<div className="col-span-2"></div>
</div>
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions src/features/shared/navbar/navbar-desktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export function NavbarDesktop({
>
<div
className={classNameObject({
"ecency-navbar-desktop max-w-[1600px] w-full mx-auto flex items-center justify-between px-4 py-3 border-b dark:border-gray-800":
"ecency-navbar-desktop max-w-[1600px] w-full mx-auto flex items-center justify-between px-4 py-3 border-b border-[--border-color]":
true,
"bg-white dark:bg-dark-700": true,
"rounded-2xl": experimental,
"bg-white dark:bg-dark-700": !experimental,
"rounded-2xl bg-white dark:bg-dark-200": experimental,
transparent: !transparentVerify && step === 1
})}
>
Expand Down
2 changes: 1 addition & 1 deletion src/features/waves/components/wave-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Props {
status: string;
entry: WaveEntry;
onEntryView: () => void;
commentsSlot: ReactNode;
commentsSlot?: ReactNode;
hasParent: boolean;
pure: boolean;
onEdit: (entry: WaveEntry) => void;
Expand Down
Loading

0 comments on commit e6cb193

Please sign in to comment.