Skip to content

Commit

Permalink
feat: implement highlight's permanent link (#957)
Browse files Browse the repository at this point in the history
Fixes #895
Fixes #950
  • Loading branch information
OgDev-01 authored Mar 9, 2023
1 parent ffa96f3 commit 78ad176
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Title from "components/atoms/Typography/title";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";

import { Textarea } from "components/atoms/Textarea/text-area";
import Button from "components/atoms/Button/button";
Expand Down Expand Up @@ -52,6 +52,7 @@ const ContributorHighlightCard = ({ title, desc, prLink, user, id }: Contributor
const [loading, setLoading] = useState(false);
const { user: loggedInUser } = useSupabaseAuth();
const [open, setOpen] = useState(false);
const [host, setHost] = useState("");

const handleCopyToClipboard = async (content: string) => {
const url = new URL(content).toString();
Expand Down Expand Up @@ -105,6 +106,12 @@ const ContributorHighlightCard = ({ title, desc, prLink, user, id }: Contributor
}
};

useEffect(() => {
if (window !== undefined) {
setHost(window.location.origin as string);
}
}, []);

return (
<article className="flex flex-col max-w-[40rem] flex-1 gap-3 lg:gap-6">
<Dialog open={open}>
Expand Down Expand Up @@ -138,7 +145,7 @@ const ContributorHighlightCard = ({ title, desc, prLink, user, id }: Contributor
<a
target="_blank"
rel="noreferrer"
href={`https://twitter.com/intent/tweet?text=${twitterTweet}&url=https://insights.opensauced.pizza/user/${user}`}
href={`https://twitter.com/intent/tweet?text=${twitterTweet}&url=${host}/feed/${id}`}
className="flex gap-2.5 py-1 items-center pl-3 pr-7"
>
<FiTwitter size={22} />
Expand All @@ -149,17 +156,14 @@ const ContributorHighlightCard = ({ title, desc, prLink, user, id }: Contributor
<a
target="_blank"
rel="noreferrer"
href={`https://www.linkedin.com/sharing/share-offsite/?url=https://insights.opensauced.pizza/user/${user}`}
href={`https://www.linkedin.com/sharing/share-offsite/?url=${host}/feed/${id}`}
className="flex gap-2.5 py-1 items-center pl-3 pr-7"
>
<FiLinkedin size={22} />
<span>Share to Linkedin</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleCopyToClipboard(`https://insights.opensauced.pizza/user/${user}`)}
className="rounded-md"
>
<DropdownMenuItem onClick={() => handleCopyToClipboard(`${host}/feed/${id}`)} className="rounded-md">
<div className="flex gap-2.5 py-1 items-center pl-3 pr-7">
<BsLink45Deg size={22} />
<span>Copy link</span>
Expand Down
7 changes: 3 additions & 4 deletions components/molecules/Dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const DialogTrigger = DialogPrimitive.Trigger;

const DialogPortal = ({ className, children, ...props }: DialogPrimitive.DialogPortalProps) => (
<DialogPrimitive.Portal className={`${className}`} {...props}>
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">{children}</div>
<div className="fixed inset-0 z-50 flex justify-center items-center">{children}</div>
</DialogPrimitive.Portal>
);
DialogPortal.displayName = DialogPrimitive.Portal.displayName;
Expand Down Expand Up @@ -53,9 +53,8 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={clsx(
"fixed z-50 grid w-full gap-4 rounded-b-lg bg-light-slate-2 p-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",

className
className,
"fixed z-50 grid w-full gap-4 rounded-b-lg bg-light-slate-2 p-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0"
)}
{...props}
>
Expand Down
14 changes: 9 additions & 5 deletions components/molecules/HighlightInput/highlight-input-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import GhOpenGraphImg from "../GhOpenGraphImg/gh-open-graph-img";
import { generateApiPrUrl } from "lib/utils/github";
import { fetchGithubPRInfo } from "lib/hooks/fetchGithubPRInfo";

const HighlightInputForm = (): JSX.Element => {
interface HighlightInputFormProps {
refreshCallback?: Function;
}

const HighlightInputForm = ({ refreshCallback }: HighlightInputFormProps): JSX.Element => {
const { user } = useSupabaseAuth();
const { mutate } = useSWRConfig();
const [isDivFocused, setIsDivFocused] = useState(false);
Expand Down Expand Up @@ -76,7 +80,6 @@ const HighlightInputForm = (): JSX.Element => {
const [url] = pullLink || [];
const highlight = bodyText.replace(url as string, "");


if (pullLink && url) {
const { apiPaths } = generateApiPrUrl(url);
const { repoName, orgName, issueId } = apiPaths;
Expand All @@ -88,7 +91,6 @@ const HighlightInputForm = (): JSX.Element => {
setLoading(false);
ToastTrigger({ message: "A valid Pull request Link is required", type: "error" });
return;

} else {
setLoading(true);
const res = await createHighlights({
Expand All @@ -99,7 +101,7 @@ const HighlightInputForm = (): JSX.Element => {

setLoading(false);
if (res) {
mutate(`users/${user?.user_metadata.user_name}/highlights`);
refreshCallback && refreshCallback();
setBodyText("");
setTitle("");
setIsDivFocused(false);
Expand All @@ -124,7 +126,9 @@ const HighlightInputForm = (): JSX.Element => {
onChange={(e) => setTitle(e.target.value)}
className=" focus:outline-none "
type="text"
placeholder={isDivFocused ? "Add title (optional)" : "Click here to highlight your merged PRs and provide a link!"}
placeholder={
isDivFocused ? "Add title (optional)" : "Click here to highlight your merged PRs and provide a link!"
}
/>
<Textarea
className={`resize-none font-normal text-light-slate-11 mb-2 transition focus:outline-none rounded-lg ${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useFetchUserHighlights } from "lib/hooks/useFetchUserHighlights";
import Button from "components/atoms/Button/button";
import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
import uppercaseFirst from "lib/utils/uppercase-first";
import Link from "next/link";

interface ContributorProfileTabProps {
contributor?: DbUser;
Expand Down Expand Up @@ -44,7 +45,7 @@ const ContributorProfileTab = ({
const { login } = contributor || {};
const { user } = useSupabaseAuth();

const { data: highlights, isError, isLoading } = useFetchUserHighlights(login || "");
const { data: highlights, isError, isLoading, mutate } = useFetchUserHighlights(login || "");
const [inputVisible, setInputVisible] = useState(false);
const pathnameRef = useRef<string | null>();

Expand All @@ -53,9 +54,8 @@ const ContributorProfileTab = ({
const hasHighlights = highlights?.length > 0;
pathnameRef.current = router.pathname.split("/").at(-1);

const currentPathname = pathnameRef.current !== "[username]"
? pathnameRef.current
: hasHighlights ? "highlights" : "contributions";
const currentPathname =
pathnameRef.current !== "[username]" ? pathnameRef.current : hasHighlights ? "highlights" : "contributions";

const handleTabUrl = (tab: string) => {
router.push(`/user/${login}/${tab.toLowerCase()}`);
Expand Down Expand Up @@ -100,7 +100,7 @@ const ContributorProfileTab = ({
/>
</div>

<HighlightInputForm />
<HighlightInputForm refreshCallback={mutate} />
</div>
)}
<div className="mt-8 flex flex-col gap-8">
Expand All @@ -115,7 +115,9 @@ const ContributorProfileTab = ({
// eslint-disable-next-line camelcase
highlights.map(({ id, title, highlight, url, created_at }) => (
<div className="flex gap-2 flex-col lg:flex-row lg:gap-7" key={id}>
<p className="text-light-slate-10 text-sm">{getFormattedDate(created_at)}</p>
<Link href={`/feed/${id}`}>
<p className="text-light-slate-10 text-sm">{getFormattedDate(created_at)}</p>
</Link>
<ContributorHighlightCard id={id} user={login || ""} title={title} desc={highlight} prLink={url} />
</div>
))
Expand Down
5 changes: 3 additions & 2 deletions lib/hooks/useFetchAllHighlights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const useFetchAllHighlights = (repo = "") => {
const limitQuery = limit ? `&limit=${limit}` : "";
const repoQuery = repo ? `&repo=${repo}` : "";

const { data, error } = useSWR<useFetchUserHighlightsResponse, Error>(
const { data, error, mutate } = useSWR<useFetchUserHighlightsResponse, Error>(
`highlights/list?${pageQuery}${limitQuery}${repoQuery}`,
publicApiFetcher as Fetcher<useFetchUserHighlightsResponse, Error>
);
Expand All @@ -24,7 +24,8 @@ const useFetchAllHighlights = (repo = "") => {
meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 },
isLoading: !error && !data,
isError: !!error,
setPage
setPage,
mutate
};
};

Expand Down
5 changes: 3 additions & 2 deletions lib/hooks/useFetchHiglightRepos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const useFetchHighlightRepos = () => {
const pageQuery = page ? `page=${page}` : "";
const limitQuery = limit ? `&limit=${limit}` : "";

const { data, error } = useSWR<useFetchUserHighlightsResponse, Error>(
const { data, error, mutate } = useSWR<useFetchUserHighlightsResponse, Error>(
`highlights/repos/list?${pageQuery}${limitQuery}`,
publicApiFetcher as Fetcher<useFetchUserHighlightsResponse, Error>
);
Expand All @@ -23,7 +23,8 @@ const useFetchHighlightRepos = () => {
meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 },
isLoading: !error && !data,
isError: !!error,
setPage
setPage,
mutate
};
};

Expand Down
20 changes: 20 additions & 0 deletions lib/hooks/useFetchSingleHighlight.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import publicApiFetcher from "lib/utils/public-api-fetcher";
import useSWR, { Fetcher } from "swr";

interface useFetchUserHighlightsResponse {
data: DbHighlight;
}
const useFetchSingleHighlight = (id: number | undefined) => {
const { data, error } = useSWR<DbHighlight, Error>(
id ? `user/highlights/${id}` : undefined,
publicApiFetcher as Fetcher<DbHighlight, Error>
);

return {
data: data ?? undefined,
isLoading: !error && !data,
isError: !!error
};
};

export { useFetchSingleHighlight };
5 changes: 3 additions & 2 deletions lib/hooks/useFetchUserHighlights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const useFetchUserHighlights = (username: string) => {

const pageQuery = page ? `page=${page}` : "";
const limitQuery = limit ? `&limit=${limit}` : "";
const { data, error } = useSWR<useFetchUserHighlightsResponse, Error>(
const { data, error, mutate } = useSWR<useFetchUserHighlightsResponse, Error>(
`users/${username}/highlights?${pageQuery}${limitQuery}`,
publicApiFetcher as Fetcher<useFetchUserHighlightsResponse, Error>
);
Expand All @@ -22,7 +22,8 @@ const useFetchUserHighlights = (username: string) => {
meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 },
isLoading: !error && !data,
isError: !!error,
setPage
setPage,
mutate
};
};

Expand Down
2 changes: 2 additions & 0 deletions pages/feed/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Feed from "../feed";
export default Feed;
69 changes: 58 additions & 11 deletions pages/feed/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import Link from "next/link";

import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
import { getFormattedDate } from "lib/utils/date-utils";
import { useFetchAllHighlights } from "lib/hooks/useFetchAllHighlights";
import { useFetchHighlightRepos } from "lib/hooks/useFetchHiglightRepos";
import { useFetchSingleHighlight } from "lib/hooks/useFetchSingleHighlight";

import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
import { Dialog, DialogCloseButton, DialogContent } from "components/molecules/Dialog/dialog";
import Avatar from "components/atoms/Avatar/avatar";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "components/atoms/Tabs/tabs";
import ContributorHighlightCard from "components/molecules/ContributorHighlight/contributor-highlight-card";
import HighlightInputForm from "components/molecules/HighlightInput/highlight-input-form";
import HighlightsFilterCard from "components/molecules/HighlightsFeedCard/highlights-filter-card";
import ProfileLayout from "layouts/profile";
import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
import { getFormattedDate } from "lib/utils/date-utils";
import { useFetchAllHighlights } from "lib/hooks/useFetchAllHighlights";
import { useFetchHighlightRepos } from "lib/hooks/useFetchHiglightRepos";
import { useEffect, useState } from "react";
import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";

const Feeds = () => {
const { user } = useSupabaseAuth();
const router = useRouter();
const { id } = router.query;
const highlightId = id as string;

const { data: repos } = useFetchHighlightRepos();

const [selectedRepo, setSelectedRepo] = useState("");

const { data, isLoading, isError } = useFetchAllHighlights(selectedRepo);
const { data, isLoading, mutate } = useFetchAllHighlights(selectedRepo);
const { data: singleHighlight } = useFetchSingleHighlight(id as unknown as number);

const repoList =
repos && // eslint-disable-next-line camelcase
Expand All @@ -36,13 +42,50 @@ const Feeds = () => {
useEffect(() => {
if (selectedRepo) {
router.push(`/feed?repo=${selectedRepo}`);
} else {
}
if (highlightId) {
router.push(`/feed/${id}`);
}
if (!highlightId && !selectedRepo) {
router.push("/feed");
}
}, [selectedRepo]);
}, [selectedRepo, highlightId]);

return (
<div className="container mx-auto px-2 md:px-16 gap-12 lg:justify-end pt-12 flex flex-col md:flex-row">
{singleHighlight && (
<Dialog open={true}>
<DialogContent className=" sm:max-w-[80%] w-full sm:max-h-[100vh] ">
<div className="mt-10 flex gap-8 flex-col mx-auto">
<div className="flex flex-col gap-6 px-3 ">
<div className="flex gap-3 items-center ">
<Avatar
alt="user profile avatar"
isCircle
size="sm"
avatarURL={`https://www.github.com/${singleHighlight.login}.png?size=300`}
/>
<strong>{singleHighlight.login}</strong>
<span className="text-xs text-light-slate-11 font-normal">
{getFormattedDate(singleHighlight.created_at)}
</span>
<DialogCloseButton onClick={() => router.push("/feed")} />
</div>

<div className=" bg-light-slate-1 border p-4 md:px-6 lg:px-12 py-6 rounded-xl">
<ContributorHighlightCard
title={singleHighlight.title}
desc={singleHighlight.highlight}
prLink={singleHighlight.url}
user={singleHighlight.login}
id={singleHighlight.id}
/>
</div>
</div>
</div>
</DialogContent>
</Dialog>
)}
<Tabs defaultValue="Highlights" className="flex-1 lg:pl-[21.875rem]">
<TabsList className="w-full border-b hidden justify-start">
<TabsTrigger
Expand Down Expand Up @@ -72,7 +115,7 @@ const Feeds = () => {
/>
</div>

<HighlightInputForm />
<HighlightInputForm refreshCallback={mutate} />
</div>
)}

Expand Down Expand Up @@ -102,7 +145,11 @@ const Feeds = () => {
/>
<strong>{login}</strong>
</Link>
<span className="text-xs text-light-slate-11 font-normal">{getFormattedDate(created_at)}</span>
<Link href={`/feed/${id}`}>
<span className="text-xs text-light-slate-11 font-normal">
{getFormattedDate(created_at)}
</span>
</Link>
</div>
<div className=" bg-light-slate-1 border p-4 md:px-6 lg:px-12 py-6 rounded-xl">
<ContributorHighlightCard title={title} desc={highlight} prLink={url} user={login} id={id} />
Expand Down

0 comments on commit 78ad176

Please sign in to comment.