Skip to content
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
27 changes: 27 additions & 0 deletions components/waves/WaveScreenMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { ReactNode } from "react";

interface WaveScreenMessageProps {
readonly title: ReactNode;
readonly description: ReactNode;
readonly action?: ReactNode;
}

export default function WaveScreenMessage({
title,
description,
action,
}: WaveScreenMessageProps) {
return (
<div className="tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-center tw-p-8 tw-text-center">
<h2 className="tw-mb-4 tw-text-xl tw-font-bold tw-text-iron-50">
{title}
</h2>
<p className="tw-mb-6 tw-max-w-md tw-text-sm tw-text-iron-400 sm:tw-text-base">
{description}
</p>
{action !== undefined && action !== null ? (
<div className="tw-flex tw-justify-center">{action}</div>
) : null}
</div>
);
}
47 changes: 22 additions & 25 deletions components/waves/WavesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import useDeviceInfo from "../../hooks/useDeviceInfo";
import PrimaryButton from "../utils/button/PrimaryButton";
import useCreateModalState from "@/hooks/useCreateModalState";
import { useMyStreamOptional } from "@/contexts/wave/MyStreamContext";
import WaveScreenMessage from "./WaveScreenMessage";

const WavesView: React.FC = () => {
const myStream = useMyStreamOptional();
Expand All @@ -22,45 +23,41 @@ const WavesView: React.FC = () => {

let content: React.ReactNode = null;


if (serialisedWaveId) {
content = (
<MyStreamWave key={`wave-${serialisedWaveId}`} waveId={serialisedWaveId} />
<MyStreamWave
key={`wave-${serialisedWaveId}`}
waveId={serialisedWaveId}
/>
);
} else if (showPlaceholder) {
content = (
<div className="tw-flex tw-flex-col tw-items-center tw-justify-center tw-h-full tw-text-center tw-p-8">
<h2 className="tw-text-xl tw-font-bold tw-text-iron-50 tw-mb-4">
Select a Wave
</h2>
<p className="tw-text-iron-400 tw-max-w-md tw-mb-6 tw-text-sm sm:tw-text-base">
Choose a wave to view its content and participate in the discussion.
</p>

{connectedProfile && (
<PrimaryButton
onClicked={openWave}
disabled={false}
loading={false}
>
<PlusIcon className="tw-w-5 tw-h-5 -tw-ml-1" />
Create Wave
</PrimaryButton>
)}
</div>
<WaveScreenMessage
title="Select a Wave"
description="Choose a wave to view its content and participate in the discussion."
action={
connectedProfile ? (
<PrimaryButton
onClicked={openWave}
disabled={false}
loading={false}
>
<PlusIcon className="-tw-ml-1 tw-h-5 tw-w-5" />
Create Wave
</PrimaryButton>
) : null
}
/>
);
}

// Note: Wave views (MyStreamWave) manage their own activeDrop state
// internally via MyStreamWaveChat. We pass null to BrainContent because
// the wave's internal state controls the reply/quote input box.
return (
<BrainContent
activeDrop={null}
onCancelReplyQuote={() => { }}>
<BrainContent activeDrop={null} onCancelReplyQuote={() => {}}>
{content}
</BrainContent>

);
};

Expand Down
42 changes: 18 additions & 24 deletions components/waves/layout/WavesLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ import { getActiveWaveIdFromUrl } from "@/helpers/navigation.helpers";
import { useAuthenticatedContent } from "../../../hooks/useAuthenticatedContent";
import useDeviceInfo from "../../../hooks/useDeviceInfo";
import ConnectWallet from "../../common/ConnectWallet";
import HeaderUserConnect from "../../header/user/HeaderUserConnect";
import UserSetUpProfileCta from "../../user/utils/set-up-profile/UserSetUpProfileCta";
import WavesDesktop from "../WavesDesktop";
import WavesMobile from "../WavesMobile";
import PublicWaveShell from "../public/PublicWaveShell";
import {
type PublicWaveShellState,
usePublicWaveShellState,
} from "../public/usePublicWaveShellState";
import WaveScreenMessage from "../WaveScreenMessage";

function getConnectPrompt(
contentState: ReturnType<typeof useAuthenticatedContent>["contentState"]
Expand Down Expand Up @@ -47,35 +45,35 @@ function getNotAuthenticatedContent({
activeWaveId,
containerClassName,
isApp,
publicWaveShellState,
isMobileDevice,
}: {
readonly activeWaveId: string | null;
readonly containerClassName: string;
readonly isApp: boolean;
readonly publicWaveShellState: PublicWaveShellState;
readonly isMobileDevice: boolean;
}): ReactNode {
if (isApp) {
if (isApp || (isMobileDevice && activeWaveId === null)) {
return <ConnectWallet />;
}

if (activeWaveId === null || publicWaveShellState.status === "unavailable") {
return <ConnectWallet />;
}

const publicShell = (
<div className={containerClassName}>
<PublicWaveShell waveId={activeWaveId} />
</div>
);

return (
<div className="tw-flex-1" id="waves-content">
<WavesDesktop
allowDropOverlay={false}
allowRightSidebar={false}
showLeftSidebar={true}
>
{publicShell}
<div className={containerClassName}>
{activeWaveId === null ? (
<WaveScreenMessage
title="Select a Wave"
description="Connect your wallet to access waves and join the conversation."
action={<HeaderUserConnect label="Connect Wallet" />}
/>
) : (
<PublicWaveShell waveId={activeWaveId} />
)}
</div>
</WavesDesktop>
</div>
);
Expand All @@ -84,14 +82,10 @@ function getNotAuthenticatedContent({
// Main layout content that uses the Layout context
function WavesLayoutContent({ children }: { readonly children: ReactNode }) {
const { contentState } = useAuthenticatedContent();
const { isApp } = useDeviceInfo();
const { isApp, isMobileDevice } = useDeviceInfo();
const pathname = usePathname();
const searchParams = useSearchParams();
const activeWaveId = getActiveWaveIdFromUrl({ pathname, searchParams });
const publicWaveShellState = usePublicWaveShellState(activeWaveId, {
enabled:
!isApp && contentState === "not-authenticated" && activeWaveId !== null,
});

const containerClassName =
"tw-relative tw-flex tw-flex-col tw-flex-1 tailwind-scope";
Expand All @@ -113,7 +107,7 @@ function WavesLayoutContent({ children }: { readonly children: ReactNode }) {
activeWaveId,
containerClassName,
isApp,
publicWaveShellState,
isMobileDevice,
});
} else {
content =
Expand Down
18 changes: 12 additions & 6 deletions components/waves/public/PublicWaveShell.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use client";

import ConnectWallet from "@/components/common/ConnectWallet";
import SpinnerLoader from "@/components/common/SpinnerLoader";
import HeaderUserConnect from "@/components/header/user/HeaderUserConnect";
import WavePicture from "@/components/waves/WavePicture";
import { formatCount } from "@/helpers/format.helpers";
import { LockClosedIcon } from "@heroicons/react/24/outline";
import WaveScreenMessage from "../WaveScreenMessage";
import LoggedOutSkeleton from "./LoggedOutSkeleton";
import {
type PublicWaveShellData,
Expand Down Expand Up @@ -34,13 +34,19 @@ function compactDescriptionText(text: string): string {
function PublicWaveLoadingState() {
return (
<div className="tw-flex tw-min-h-full tw-flex-1 tw-flex-col tw-items-center tw-justify-center tw-py-8">
<SpinnerLoader text="Loading wave overview..." />
<SpinnerLoader text="Loading wave..." />
</div>
);
}

function PublicWaveUnavailableState() {
return <ConnectWallet />;
return (
<WaveScreenMessage
title="This wave isn't available publicly"
description="Connect your wallet to check whether you have access."
action={<HeaderUserConnect label="Connect Wallet" />}
/>
);
}

function PublicWaveShellContent({
Expand Down Expand Up @@ -73,19 +79,19 @@ function PublicWaveShellContent({

<div className="tw-relative tw-z-10 tw-flex tw-flex-col tw-items-center tw-px-6 tw-pb-10 tw-pt-10 tw-text-center md:tw-px-10">
<div className="tw-mb-1 tw-flex tw-max-w-md tw-flex-col tw-items-center tw-justify-center tw-gap-4">
<div className="tw-size-12 tw-flex-shrink-0 tw-overflow-hidden tw-rounded-full tw-ring-1 tw-ring-white/10 tw-ring-offset-4 tw-ring-offset-iron-950 tw-shadow-2xl sm:tw-size-14">
<div className="tw-size-12 tw-flex-shrink-0 tw-overflow-hidden tw-rounded-full tw-shadow-2xl tw-ring-1 tw-ring-white/10 tw-ring-offset-4 tw-ring-offset-iron-950 sm:tw-size-14">
<WavePicture
name={wave.name}
picture={wave.picture}
contributors={[]}
/>
</div>
<h2 className="tw-mb-2 tw-text-white tw-text-xl tw-font-semibold tw-leading-[1.05] tw-tracking-tighter tw-text-transparent sm:tw-text-2xl md:tw-text-3xl">
<h2 className="tw-mb-2 tw-text-xl tw-font-semibold tw-leading-[1.05] tw-tracking-tighter tw-text-transparent tw-text-white sm:tw-text-2xl md:tw-text-3xl">
{wave.name}
</h2>
</div>
{hasDescription && (
<p className="tw-mb-10 tw-pb-0 tw-max-w-md tw-text-pretty tw-text-sm tw-font-normal tw-text-iron-400 md:tw-text-md">
<p className="tw-mb-10 tw-max-w-md tw-text-pretty tw-pb-0 tw-text-sm tw-font-normal tw-text-iron-400 md:tw-text-md">
{description}
</p>
)}
Expand Down
2 changes: 1 addition & 1 deletion components/waves/public/usePublicWaveShellState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface PublicWaveShellData {
readonly postsCount: number;
}

export type PublicWaveShellState =
type PublicWaveShellState =
| { readonly status: "loading" }
| { readonly status: "unavailable" }
| { readonly status: "ready"; readonly wave: PublicWaveShellData };
Expand Down
Loading