Skip to content

Commit

Permalink
Merge pull request #31 from pierobassa/refactor-profile-page
Browse files Browse the repository at this point in the history
refactor: profile page
  • Loading branch information
akanoce committed Sep 24, 2023
2 parents 1999ac7 + 2736497 commit 83a9f48
Show file tree
Hide file tree
Showing 31 changed files with 1,077 additions and 80 deletions.
6 changes: 6 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
NEXT_PLUBIC_ALCHEMY_API_KEY=6TSi2tIhA_BevqqnVA1ouoyfgWw7Iqhz
NEXT_PUBLIC_INFURA_API_KEY=95dc17d3b1c343d2b3b4a5bdbd8182ef
NEXT_PUBLIC_CONTRACT_ADDRESS=0x12E22b5e0c08ba383c464dB316dE7C43f123482f
NEXT_PUBLIC_RPC_URL=https://polygon-mumbai.infura.io/v3/95dc17d3b1c343d2b3b4a5bdbd8182ef
NEXT_PUBLIC_WEB3_STORAGE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweDdFRjBiYUVCMGMwMzRGQTkzODBjZDU1MTIzOEZhN0VhNDE4RTQzYkIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2OTU0Mzc4ODMwMjEsIm5hbWUiOiJSdWJ5UmluZyJ9.h8WPmstkhzlR4QN_nnblYjARR7Sym4xEwxxSM9P3yDo
NEXT_PUBLIC_BACKEND_URL=http://127.0.0.1:8000
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

!env.local
# vercel
.vercel

Expand Down
6 changes: 3 additions & 3 deletions src/components/AccountCard/AccountCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export default function AccountCard({
</div>

<div className="py-6">
<BaseSeparator color="#444444" />
<BaseSeparator className="w-full h-1 bg-#444444" />
</div>

<div className="flex flex-row items-center justify-center text-sm">
Expand Down Expand Up @@ -148,7 +148,7 @@ export default function AccountCard({
</div>

<div className="py-6">
<BaseSeparator color="#444444" />
<BaseSeparator className="w-full h-1 bg-#444444" />
</div>

<div className="flex flex-row items-center justify-center text-sm">
Expand Down Expand Up @@ -180,7 +180,7 @@ export default function AccountCard({
</div>

<div className="py-6">
<BaseSeparator color="#444444" />
<BaseSeparator className="w-full h-1 bg-#444444" />
</div>

<div>
Expand Down
14 changes: 3 additions & 11 deletions src/components/Base/BaseSeparator/BaseSeparator.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
type Props = {
color: string;
className?: string;
};

export const BaseSeparator = ({ color }: Props) => {
return (
<div
style={{
backgroundColor: color,
width: "100%",
height: 1
}}
/>
);
export const BaseSeparator = ({ className = "h-1 bg-white w-full" }: Props) => {
return <div className={className} />;
};
220 changes: 220 additions & 0 deletions src/components/Lens/CreatePost/CreatePost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
import { web3StorageClient } from "@/networking";
import { useAccountStore } from "@/store";
import { ContentFocus, useCreatePost } from "@lens-protocol/react-web";
import { ChangeEvent, useCallback, useMemo, useState } from "react";
import { getWeb3StorageLink } from "../CreateLensProfileForm/helpers";
import toast from "react-hot-toast";
import { FaGem } from "react-icons/fa";
import { BeatLoader } from "react-spinners";

type Props = {
refetchPublications: () => void;
};

function classNames(...classes: string[]) {
return classes.filter(Boolean).join(" ");
}

export default function CreatePost({ refetchPublications }: Props) {
const { lensAccount } = useAccountStore();

const [postText, setPostText] = useState<string>("");

const [loading, setLoading] = useState<boolean>(false);

const upload = useCallback(async (data: unknown): Promise<string> => {
const serialized = JSON.stringify(data);

const blob = new Blob([serialized], { type: "application/json" });

const name = blob.name;

const cid = await web3StorageClient.put([new File([blob], name)]);

const web3StorageIPFSurl = getWeb3StorageLink(cid);

const url = `${web3StorageIPFSurl}/${name}`;

return url;
}, []);

// TODO: Add error handling and loading state
const {
execute: createPost
// error,
// isPending
} = useCreatePost({
publisher: lensAccount!,
upload
});

const handleOnTextChange = useCallback(
(event: ChangeEvent<HTMLTextAreaElement>) => {
const value = event.target.value;

setPostText(value);
},
[]
);

const onPostCreate = useCallback(async () => {
try {
setLoading(true);

await createPost({
content: postText,
contentFocus: ContentFocus.TEXT_ONLY,
locale: "en"
});

refetchPublications();

toast.success("Post published to your Ring");
setLoading(false);

setPostText("");
} catch (error) {
console.error(error);
setLoading(false);

toast.error("Oops! Something went wrong, try again.");
}
}, [createPost, postText, refetchPublications]);

const isPostDisabled = useMemo(() => {
return postText.length === 0;
}, [postText]);

return (
<>
<div className="w-full mb-4 border rounded-lg bg-[#2b2b2b] border-gray-600">
<div className="flex items-center justify-between px-3 py-2 border-b border-gray-600">
<div className="flex flex-wrap items-center sm:divide-x divide-gray-600">
<div className="flex items-center space-x-1 sm:pr-4">
<button
type="button"
className="p-2 rounded cursor-pointer text-[#ff89a9] hover:text-white hover:bg-gray-600"
>
<svg
className="w-4 h-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 12 20"
>
<path
stroke="currentColor"
stroke-linejoin="round"
stroke-width="2"
d="M1 6v8a5 5 0 1 0 10 0V4.5a3.5 3.5 0 1 0-7 0V13a2 2 0 0 0 4 0V6"
/>
</svg>
<span className="sr-only">Attach file</span>
</button>
<button
type="button"
className="p-2 rounded cursor-pointer text-[#ff89a9] hover:text-white hover:bg-gray-600"
>
<svg
className="w-4 h-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 16 20"
>
<path d="M8 0a7.992 7.992 0 0 0-6.583 12.535 1 1 0 0 0 .12.183l.12.146c.112.145.227.285.326.4l5.245 6.374a1 1 0 0 0 1.545-.003l5.092-6.205c.206-.222.4-.455.578-.7l.127-.155a.934.934 0 0 0 .122-.192A8.001 8.001 0 0 0 8 0Zm0 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" />
</svg>
<span className="sr-only">Embed map</span>
</button>
<button
type="button"
className="p-2 rounded cursor-pointer text-[#ff89a9] hover:text-white hover:bg-gray-600"
>
<svg
className="w-4 h-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 16 20"
>
<path d="M14.066 0H7v5a2 2 0 0 1-2 2H0v11a1.97 1.97 0 0 0 1.934 2h12.132A1.97 1.97 0 0 0 16 18V2a1.97 1.97 0 0 0-1.934-2ZM10.5 6a1.5 1.5 0 1 1 0 2.999A1.5 1.5 0 0 1 10.5 6Zm2.221 10.515a1 1 0 0 1-.858.485h-8a1 1 0 0 1-.9-1.43L5.6 10.039a.978.978 0 0 1 .936-.57 1 1 0 0 1 .9.632l1.181 2.981.541-1a.945.945 0 0 1 .883-.522 1 1 0 0 1 .879.529l1.832 3.438a1 1 0 0 1-.031.988Z" />
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.98 2.98 0 0 0 .13 5H5Z" />
</svg>
<span className="sr-only">Upload image</span>
</button>
<button
type="button"
className="p-2 rounded cursor-pointer text-[#ff89a9] hover:text-white hover:bg-gray-600"
>
<svg
className="w-4 h-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 16 20"
>
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z" />
<path d="M14.067 0H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18V2a1.97 1.97 0 0 0-1.933-2ZM6.709 13.809a1 1 0 1 1-1.418 1.409l-2-2.013a1 1 0 0 1 0-1.412l2-2a1 1 0 0 1 1.414 1.414L5.412 12.5l1.297 1.309Zm6-.6-2 2.013a1 1 0 1 1-1.418-1.409l1.3-1.307-1.295-1.295a1 1 0 0 1 1.414-1.414l2 2a1 1 0 0 1-.001 1.408v.004Z" />
</svg>
<span className="sr-only">Format code</span>
</button>
<button
type="button"
className="p-2 rounded cursor-pointer text-[#ff89a9] hover:text-white hover:bg-gray-600"
>
<svg
className="w-4 h-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM13.5 6a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm-7 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm3.5 9.5A5.5 5.5 0 0 1 4.6 11h10.81A5.5 5.5 0 0 1 10 15.5Z" />
</svg>
<span className="sr-only">Add emoji</span>
</button>
</div>
</div>
</div>
<div className="px-4 py-2 rounded-b-lg bg-[#434343]">
<textarea
id="editor"
rows={8}
value={postText}
className="block w-full px-0 text-sm border-0 bg-[#434343] text-white placeholder-stone-200 ring-black ring-opacity-5 focus:outline-none"
placeholder="What are you thinking..."
required
onChange={handleOnTextChange}
/>
</div>
</div>
<button
onClick={onPostCreate}
className={classNames(
"bg-[#FF89A9] flex justify-center items-center rounded-md text-[#2b2b2b] mt-4 px-6 w-42",
isPostDisabled
? "cursor-not-allowed brightness-75"
: " hover:brightness-90"
)}
disabled={isPostDisabled}
>
{loading ? (
<div className="py-2 px-8">
<BeatLoader
color={"white"}
loading={true}
size={8}
aria-label="Loading Spinner"
data-testid="loader"
/>
</div>
) : (
<>
<p className="py-2 px-2 font-medium uppercase text-base">Publish</p>
<FaGem />
</>
)}
</button>
</>
);
}
1 change: 1 addition & 0 deletions src/components/Lens/CreatePost/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./CreatePost";
29 changes: 29 additions & 0 deletions src/components/Lens/Publications/LensPublication.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { FaGem } from "react-icons/fa";

type Props = {
content: string;
imageUrl: string;
lensHandle: string;
};

export const LensPublication = ({ content, imageUrl, lensHandle }: Props) => {
return (
<div className="flex flex-col items-center justify-center p-8 text-center border-b rounded-lg md:rounded-tl-lg md:border-r bg-stone-800 border-stone-700">
<FaGem className="text-[#fe87a2] text-2xl" />
<blockquote className="max-w-2xl mx-auto mb-4 00 lg:mb-8 text-gray-400">
<p className="my-4">{content}</p>
</blockquote>
<div className="flex items-center justify-center space-x-3">
<img
className="rounded-full w-9 h-9"
src={imageUrl}
alt="profile picture"
/>
<div className="space-y-0.5 font-medium text-white text-left">
<div>{lensHandle}</div>
<div className="text-sm text-gray-400">Early user of Ruby Ring</div>
</div>
</div>
</div>
);
};
60 changes: 60 additions & 0 deletions src/components/Lens/Publications/Publications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { AnyPublication } from "@lens-protocol/react-web";
import { LensPublication } from ".";
import { useCallback } from "react";
import { BaseSeparator } from "@/components";

type Props = {
publications: AnyPublication[];
imageUrl: string;
lensHandle: string;
};

export default function Publications({
publications,
imageUrl,
lensHandle
}: Props) {
//TODO: support mirror posts
const getPublicationContent = useCallback((publication: AnyPublication) => {
if (publication.__typename === "Post") {
const content = publication.metadata.content ?? "";

if (content.length > 100) {
return `${content.substring(0, 100)}...`;
}

return content;
}
return "";
}, []);

return (
<div className="w-full flex flex-col md:flex-row gap-4 justify-between items-stretch flex-wrap">
{!publications.length ? (
<div className="w-full flex flex-col items-center justify-center">
<div className="text-2xl font-bold">No posts yet</div>
<div className="text-lg font-medium text-gray-500">
{lensHandle} has not posted anything yet
</div>
</div>
) : (
<div className="w-full flex flex-col justify-center gap-2">
<BaseSeparator className="w-full h-0.5 bg-stone-500" />
<div className="text-lg font-medium text-gray-500">
{publications.length} posts
</div>

{publications.map((publication) => (
<div key={publication.id} className="w-full md:w-[30%]">
<LensPublication
content={getPublicationContent(publication)}
imageUrl={imageUrl}
lensHandle={lensHandle}
/>
</div>
))}
</div>
)}
</div>
);
}
2 changes: 2 additions & 0 deletions src/components/Lens/Publications/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./Publications";
export * from "./LensPublication";
2 changes: 2 additions & 0 deletions src/components/Lens/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export * from "./AddProfilePictureForm";
export * from "./CreateLensProfileForm";
export * from "./CreatePost";
export * from "./ConnectedAccountProfileCard";
export * from "./LensProfileCard";
export * from "./Publications";
export * from "./SearchLensProfiles";
export * from "./SpotlightSearchLensProfiles";
export * from "./SelectLensProfile";
Loading

0 comments on commit 83a9f48

Please sign in to comment.