Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Create lazy loading #113

Open
wants to merge 7 commits into
base: prototype
Choose a base branch
from
Open
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
129 changes: 67 additions & 62 deletions src/components/Activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,79 @@ import { useEffect, useState } from "react";
import { client } from "@/config/appwrite-client";

export default function Activity() {
const [activity, setActivity] = useState([]);
const [activity, setActivity] = useState([]);

const getActivity = async () => {
const res = await fetch("/api/activity");
const data = await res.json();
setActivity(data);
};
const getActivity = async () => {
const res = await fetch("/api/activity");
const data = await res.json();
setActivity(data);
};

useEffect(() => {
const events = [
`databases.${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID}.collections.${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_RATINGS_ID}.documents`,
];
client.subscribe(events, () => getActivity());
getActivity();
}, []);
useEffect(() => {
const events = [
`databases.${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID}.collections.${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_RATINGS_ID}.documents`,
];
client.subscribe(events, () => getActivity());
getActivity();
}, []);

return (
<>
<header className="flex items-center justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
<h2 className="text-base font-semibold leading-7 text-white">
Activity feed
</h2>
{/* <a
return (
<>
<header className="flex items-center justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
<h2 className="text-base font-semibold leading-7 text-white">
Activity feed
</h2>
{/* <a
href="#"
className="text-sm font-semibold leading-6 text-indigo-400"
>
View all
</a> */}
</header>
<ul role="list" className="divide-y divide-white/5">
{activity.map((rating, idx) => (
<li key={idx} className="px-4 py-4 sm:px-6 lg:px-8">
<div className="flex items-center gap-x-3">
<Link
href={`https://github.com/${rating.username}`}
target="_blank"
>
<Image
className="h-6 w-6 flex-none rounded-full bg-gray-800"
src={`https://github.com/${rating.username}.png`}
alt={`Logo for ${rating.name}`}
width={20}
height={20}
/>
</Link>
<Link
href={`https://github.com/${rating.username}`}
target="_blank"
className="flex-auto truncate text-sm font-semibold leading-6 text-white"
>
{rating.username}
</Link>
<time
dateTime={rating.$updatedAt}
className="flex-none text-xs text-gray-600"
>
{rating.timeAgo}
</time>
</div>
<p className="mt-3 truncate text-sm text-gray-500">
Rated{" "}
<Link className="text-gray-400" href={rating.url} target="_blank">
{rating.url.split("github.com/")[1]}
</Link>
</p>
</li>
))}
</ul>
</>
);
</header>
<ul role="list" className="divide-y divide-white/5">
{activity.map((rating, idx) => (
<li key={idx} className="px-4 py-4 sm:px-6 lg:px-8">
<div className="flex items-center gap-x-3">
<Link
href={`https://github.com/${rating.username}`}
target="_blank"
>
<Image
className="h-6 w-6 flex-none rounded-full bg-gray-800"
src={`https://github.com/${rating.username}.png`}
alt={`Logo for ${rating.name}`}
width={20}
height={20}
/>
</Link>
<Link
href={`https://github.com/${rating.username}`}
target="_blank"
className="flex-auto truncate text-sm font-semibold leading-6 text-white"
>
{rating.username}
</Link>
<time
dateTime={rating.$updatedAt}
className="flex-none text-xs text-gray-600"
>
{rating.timeAgo}
</time>
</div>
<p className="mt-3 truncate text-sm text-gray-500">
Rated{" "}
<Link
href={`/rate?owner=${
rating.url.split("github.com/")[1].split("/")[0]
}&name=${rating.url.split("github.com/")[1].split("/")[1]}`}
className="text-gray-400"
>
{rating.url.split("github.com/")[1]}
</Link>
</p>
</li>
))}
</ul>
</>
);
}
12 changes: 12 additions & 0 deletions src/components/ListSkeletons/RepoListSkeleton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const RepoListSkeleton = () => {
return (
<div className="w-11/12 mx-auto">
<div className="w-full flex items-center my-4">
<div className="skeleton w-20 h-20 bg-slate-900 rounded-none mt-4 lg:mt-0"></div>
<div className="skeleton w-full h-20 bg-slate-900 mx-4 rounded-none mt-4 lg:mt-0"></div>
</div>
</div>
);
};

export default RepoListSkeleton;
175 changes: 56 additions & 119 deletions src/components/Repos.js
Original file line number Diff line number Diff line change
@@ -1,138 +1,75 @@
"use client";

import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import { ChevronRightIcon } from "@heroicons/react/20/solid";
import dynamic from "next/dynamic";

import { client } from "@/config/appwrite-client";
import { classNames } from "@/utils/classNames";
import RepoListSkeleton from "./ListSkeletons/RepoListSkeleton";

const RepoList = dynamic(() => import("./componentList/RepoList"), {
loading: RepoListSkeleton,
ssr: false,
});

const statuses = {
research: "text-orange-500 bg-orange-100/10",
recommend: "text-green-400 bg-green-400/10",
caution: "text-rose-400 bg-rose-400/10",
};
const badges = {
research: "text-orange-500 bg-orange-100/10 ring-orange-400/20",
recommend: "text-green-400 bg-green-400/10 ring-green-400/20",
caution: "text-rose-400 bg-rose-400/10 ring-rose-400/20",
};
const groups = {
recommend: 70,
research: 40,
recommend: 70,
research: 40,
};

const calStatus = (percentage) => {
if (percentage >= groups.recommend) {
return "recommend";
}
if (percentage >= groups.research && percentage < groups.recommend) {
return "research";
}
return "caution";
if (percentage >= groups.recommend) {
return "recommend";
}
if (percentage >= groups.research && percentage < groups.recommend) {
return "research";
}
return "caution";
};

export default function Repos({ minimumVotes = 5, keyword, sort }) {
const [repos, setRepos] = useState([]);
const getRepos = async () => {
const params = [];
if (minimumVotes) {
params.push(`minimumVotes=${minimumVotes}`);
}
if (keyword) {
params.push(`keyword=${keyword}`);
}
if (sort) {
params.push(`sort=${sort}`);
}
const res = await fetch(
`/api/repos${params.length ? `?${params.join("&")}` : ""}`
);
const [repos, setRepos] = useState([]);
const getRepos = async () => {
const params = [];
if (minimumVotes) {
params.push(`minimumVotes=${minimumVotes}`);
}
if (keyword) {
params.push(`keyword=${keyword}`);
}
if (sort) {
params.push(`sort=${sort}`);
}
const res = await fetch(
`/api/repos${params.length ? `?${params.join("&")}` : ""}`
);

const data = await res.json();
const data = await res.json();

const repos = data.map((repo) => {
const percentage = Math.round((repo.rating / 5) * 100);
return {
...repo,
percentage,
status: calStatus(percentage),
};
});
const repos = data.map((repo) => {
const percentage = Math.round((repo.rating / 5) * 100);
return {
...repo,
percentage,
status: calStatus(percentage),
};
});

setRepos(repos);
};
setRepos(repos);
};

useEffect(() => {
const events = [
`databases.${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID}.collections.${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_REPOS_ID}.documents`,
];
client.subscribe(events, () => getRepos());
getRepos();
}, [keyword, sort]);
useEffect(() => {
const events = [
`databases.${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID}.collections.${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_REPOS_ID}.documents`,
];
client.subscribe(events, () => getRepos());
getRepos();
}, [keyword, sort]);

return (
<ul role="list" className="divide-y divide-white/5">
{repos.map((repo, idx) => (
<li
key={idx}
className="relative flex items-center space-x-4 px-4 py-4 sm:px-6 lg:px-8"
>
<Image
className="inline-block rounded-md h-12 w-12"
src={repo.logo}
alt={`Logo for ${repo.owner}/${repo.name}`}
width={40}
height={40}
/>
<div className="min-w-0 flex-auto">
<div className="flex items-center gap-x-3">
<div
className={classNames([
statuses[repo.status],
"flex-none rounded-full p-1",
])}
>
<div className="h-2 w-2 rounded-full bg-current" />
</div>
<h2 className="min-w-0 text-sm font-semibold leading-6 text-white">
<Link
href={`/rate?owner=${repo.owner}&name=${repo.name}`}
className="flex gap-x-2"
>
<span className="truncate">{repo.owner}</span>
<span className="text-gray-400">/</span>
<span className="whitespace-nowrap">{repo.name}</span>
<span className="absolute inset-0" />
</Link>
</h2>
</div>
<div className="mt-3 flex items-center gap-x-2.5 text-xs leading-5 text-gray-400">
<p className="truncate">{repo.description}</p>
<svg
viewBox="0 0 2 2"
className="h-0.5 w-0.5 flex-none fill-gray-300"
>
<circle cx={1} cy={1} r={1} />
</svg>
<p className="whitespace-nowrap">{repo.status}</p>
</div>
</div>
<div
className={classNames([
badges[repo.status],
"rounded-full flex-none py-1 px-2 text-xs font-medium ring-1 ring-inset",
])}
>
{repo.rating.toFixed(1)} / 5 ({repo.votes})
</div>
<ChevronRightIcon
className="h-5 w-5 flex-none text-gray-400"
aria-hidden="true"
/>
</li>
))}
</ul>
);
return (
<ul role="list" className="divide-y divide-white/5">
{repos.map((repo, idx) => (
<RepoList key={idx} repo={repo} />
))}
</ul>
);
}
2 changes: 1 addition & 1 deletion src/components/SideNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default function SideNav({ setKeyword, children }) {
account.createOAuth2Session(
"github",
`${process.env.NEXT_PUBLIC_BASE_URL}/`,
`${process.env.NEXT_PUBLIC_BASE_URL}/`
`${process.env.NEXT_PUBLIC_BASE_URL}/`,
);
};

Expand Down
Loading