This commit is contained in:
Ren Amamiya
2023-06-24 18:31:40 +07:00
parent 21d22320b3
commit 85b30f770c
102 changed files with 1844 additions and 2014 deletions

View File

@@ -5,20 +5,24 @@ import { AvatarUploader } from "@shared/avatarUploader";
import { CancelIcon, LoaderIcon, PlusIcon } from "@shared/icons";
import { Image } from "@shared/image";
import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts";
import { DEFAULT_AVATAR } from "@stores/constants";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { dateToUnix } from "@utils/date";
import { useAccount } from "@utils/hooks/useAccount";
import { Fragment, useContext, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { navigate } from "vite-plugin-ssr/client/router";
import { useNavigate } from "react-router-dom";
export function ChannelCreateModal() {
const ndk = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account);
const queryClient = useQueryClient();
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState(false);
const [image, setImage] = useState(DEFAULT_AVATAR);
const [loading, setLoading] = useState(false);
const [image, setImage] = useState(DEFAULT_AVATAR);
const { account } = useAccount();
const closeModal = () => {
setIsOpen(false);
@@ -36,6 +40,21 @@ export function ChannelCreateModal() {
formState: { isDirty, isValid },
} = useForm();
const addChannel = useMutation({
mutationFn: (event: any) =>
createChannel(
event.id,
event.pubkey,
event.name,
event.picture,
event.about,
event.created_at,
),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["channels"] });
},
});
const onSubmit = (data: any) => {
setLoading(true);
@@ -55,7 +74,12 @@ export function ChannelCreateModal() {
event.publish();
// insert to database
createChannel(event.id, event.pubkey, event.content, event.created_at);
addChannel.mutate({
...event,
name: data.name,
picture: data.picture,
about: data.about,
});
// reset form
reset();
@@ -64,7 +88,7 @@ export function ChannelCreateModal() {
// close modal
setIsOpen(false);
// redirect to channel page
navigate(`/app/channel?id=${event.id}`);
navigate(`/app/channel/${event.id}`);
}, 1000);
} catch (e) {
console.log("error: ", e);

View File

@@ -1,29 +1,20 @@
import { useChannelProfile } from "@app/channel/hooks/useChannelProfile";
import { Link } from "@shared/link";
import { usePageContext } from "@utils/hooks/usePageContext";
import { NavLink } from "react-router-dom";
import { twMerge } from "tailwind-merge";
export function ChannelsListItem({ data }: { data: any }) {
const channel: any = useChannelProfile(data.event_id);
const pageContext = usePageContext();
const searchParams: any = pageContext.urlParsed.search;
const pageID = searchParams.id;
const channel = useChannelProfile(data.event_id);
return (
<Link
href={`/app/channel?id=${data.event_id}`}
className={twMerge(
"inline-flex h-9 items-center gap-2.5 rounded-md px-2.5",
pageID === data.event_id ? "bg-zinc-900 text-zinc-100" : "",
)}
<NavLink
to={`/app/channel/${data.event_id}`}
className={({ isActive }) =>
twMerge(
"inline-flex h-9 items-center gap-2.5 rounded-md px-2.5",
isActive ? "bg-zinc-900/50 text-zinc-100" : "",
)
}
>
<div
className={twMerge(
"inline-flex shrink-0 h-6 w-6 items-center justify-center rounded border-t border-zinc-800/50 bg-zinc-900",
pageID === data.event_id ? "bg-zinc-800" : "",
)}
>
<div className="inline-flex shrink-0 h-6 w-6 items-center justify-center rounded border-t border-zinc-800/50 bg-zinc-900">
<span className="text-xs text-zinc-100">#</span>
</div>
<div className="w-full inline-flex items-center justify-between">
@@ -36,6 +27,6 @@ export function ChannelsListItem({ data }: { data: any }) {
)}
</div>
</div>
</Link>
</NavLink>
);
}

View File

@@ -1,27 +1,36 @@
import { ChannelCreateModal } from "@app/channel/components/createModal";
import { ChannelsListItem } from "@app/channel/components/item";
import { useChannels } from "@stores/channels";
import { useEffect } from "react";
import { getChannels } from "@libs/storage";
import { useQuery } from "@tanstack/react-query";
export function ChannelsList() {
const channels = useChannels((state: any) => state.channels);
const fetchChannels = useChannels((state: any) => state.fetch);
useEffect(() => {
fetchChannels();
}, [fetchChannels]);
const {
status,
data: channels,
isFetching,
} = useQuery(
["channels"],
async () => {
return await getChannels();
},
{
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
},
);
return (
<div className="flex flex-col">
{!channels ? (
{status === "loading" ? (
<>
<div className="inline-flex h-9 items-center gap-2 rounded-md px-2.5">
<div className="relative h-5 w-5 shrink-0 animate-pulse rounded bg-zinc-800" />
<div className="h-3 w-full animate-pulse rounded-sm bg-zinc-800" />
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5">
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-zinc-800" />
<div className="h-3.5 w-full animate-pulse rounded-sm bg-zinc-800" />
</div>
<div className="inline-flex h-9 items-center gap-2 rounded-md px-2.5">
<div className="relative h-5 w-5 shrink-0 animate-pulse rounded bg-zinc-800" />
<div className="h-3 w-full animate-pulse rounded-sm bg-zinc-800" />
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5">
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-zinc-800" />
<div className="h-3.5 w-full animate-pulse rounded-sm bg-zinc-800" />
</div>
</>
) : (
@@ -29,6 +38,12 @@ export function ChannelsList() {
<ChannelsListItem key={item.event_id} data={item} />
))
)}
{isFetching && (
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5">
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-zinc-800" />
<div className="h-3.5 w-full animate-pulse rounded-sm bg-zinc-800" />
</div>
)}
<ChannelCreateModal />
</div>
);

View File

@@ -1,11 +1,14 @@
import { Member } from "@app/channel/components/member";
import { getChannelUsers } from "@libs/storage";
import useSWR from "swr";
const fetcher = ([, id]) => getChannelUsers(id);
import { useQuery } from "@tanstack/react-query";
export function ChannelMembers({ id }: { id: string }) {
const { data, isLoading }: any = useSWR(["channel-members", id], fetcher);
const { status, data, isFetching } = useQuery(
["channel-members", id],
async () => {
return await getChannelUsers(id);
},
);
return (
<div className="mt-3">
@@ -13,8 +16,7 @@ export function ChannelMembers({ id }: { id: string }) {
Members
</h5>
<div className="mt-3 w-full flex flex-wrap gap-1.5">
{isLoading && <p>Loading...</p>}
{!data ? (
{status === "loading" || isFetching ? (
<p>Loading...</p>
) : (
data.map((member: { pubkey: string }) => (

View File

@@ -3,14 +3,13 @@ import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
import { CancelIcon, EnterIcon } from "@shared/icons";
import { MediaUploader } from "@shared/mediaUploader";
import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts";
import { useChannelMessages } from "@stores/channels";
import { dateToUnix } from "@utils/date";
import { useAccount } from "@utils/hooks/useAccount";
import { useContext, useState } from "react";
export function ChannelMessageForm({ channelID }: { channelID: string }) {
const ndk = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account);
const [value, setValue] = useState("");
const [replyTo, closeReply] = useChannelMessages((state: any) => [
@@ -18,6 +17,8 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
state.closeReply,
]);
const { account } = useAccount();
const submit = () => {
let tags: string[][];