Skip to content

feat: create list feature #1698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
14ced90
feat: hub list feature initial commit
OgDev-01 Sep 7, 2023
bd6633d
Merge branch 'beta' of https://github.com/open-sauced/insights into 1…
OgDev-01 Sep 8, 2023
10de192
fix: list CTA button alignment
OgDev-01 Sep 9, 2023
f15717e
chore: add type for list contributors
OgDev-01 Sep 11, 2023
66e2797
refactor: replace dummy contributors with live data
OgDev-01 Sep 11, 2023
669372f
feat: add fetch hooks for lists and contributors
OgDev-01 Sep 11, 2023
4c2d63a
refactor: breakout tabs and add loader
OgDev-01 Sep 11, 2023
9e3b074
fix: build error
OgDev-01 Sep 11, 2023
1bf47b4
refactor: switch from tabs to pages
OgDev-01 Sep 12, 2023
3d5bacd
fix: link href location
OgDev-01 Sep 12, 2023
fb377a3
refactor: add proper redirect to insights from hub
OgDev-01 Sep 12, 2023
97d90ed
feat: add filter chip component to design system
OgDev-01 Sep 12, 2023
d7b8a22
style: update date filter styles
OgDev-01 Sep 13, 2023
62b4c77
feat: create contributor hub header component
OgDev-01 Sep 13, 2023
b9d76df
chore: update header component props
OgDev-01 Sep 13, 2023
61c3866
feat: add comtributors hub layout
OgDev-01 Sep 13, 2023
2b53581
chore: initial commit for hub contributors table implementation
OgDev-01 Sep 13, 2023
43ece18
Merge branch 'beta' of https://github.com/open-sauced/insights into 1…
OgDev-01 Sep 14, 2023
0627cbb
chore: add contributor list global type
OgDev-01 Sep 14, 2023
b950edb
feat: implement contributor selct
OgDev-01 Sep 14, 2023
d4afed9
chore: minor layout updates and cleeanup
OgDev-01 Sep 14, 2023
ee6bc8a
Merge branch 'beta' into 1665-explore-contributors
OgDev-01 Sep 14, 2023
4b47408
chore: add pagination layers
OgDev-01 Sep 14, 2023
709e5ed
Merge branch '1665-explore-contributors' of https://github.com/open-s…
OgDev-01 Sep 14, 2023
48475c7
Merge branch 'beta' of https://github.com/open-sauced/insights into 1…
OgDev-01 Sep 14, 2023
8527dc1
Merge branch 'beta' into 1665-explore-contributors
OgDev-01 Sep 14, 2023
5eadc21
feat: finishing touches on create list
OgDev-01 Sep 15, 2023
2967de0
misc: review changes
OgDev-01 Sep 18, 2023
766c8f9
refactor: remove unused code and comments
OgDev-01 Sep 18, 2023
0bb2503
misc: styles update
OgDev-01 Sep 18, 2023
1a9a902
refactor: update title component logic
OgDev-01 Sep 18, 2023
9e79f6f
feat: add switch for isPublic
OgDev-01 Sep 20, 2023
c0b815e
feat: add mozilla firefox prefix plugin to tailwind
OgDev-01 Sep 20, 2023
6858893
Merge branch 'beta' into 1665-explore-contributors
OgDev-01 Sep 20, 2023
671e337
misc: remove console logs
OgDev-01 Sep 20, 2023
c2eb8e2
fix: mobile responsiveness
OgDev-01 Sep 21, 2023
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
25 changes: 25 additions & 0 deletions components/atoms/FilterChip/filter-chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import clsx from "clsx";
import React from "react";
import { MdClose } from "react-icons/md";

interface FilterChipProps {
className?: string;
items: string[];
onClear: () => void;
}
const FilterChip = ({ className, items, onClear }: FilterChipProps) => {
return (
<div
className={clsx(
"p-2.5 rounded-xl bg-sauced-light w-max text-sauced-orange max-w-[12.5rem] flex items-center",
className
)}
>
<span className="max-w-[75%] truncate">{items[0]}</span>
{items.length > 1 && <span className="text-sauced-orange"> ,+{items.length - 1}</span>}
<MdClose onClick={onClear} className="ml-1 text-2xl" />
</div>
);
};

export default FilterChip;
64 changes: 41 additions & 23 deletions components/atoms/ListNameHeader/list-name-header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useRef } from "react";
import React, { useRef, useState } from "react";
import { HiPencil } from "react-icons/hi";
import clsx from "clsx";

Expand All @@ -9,36 +9,54 @@ interface ListNameHeaderProps {
onEditTitle?: (value: string) => void;
}
const ListNameHeader = ({ title, onEditTitle }: ListNameHeaderProps) => {
const ref = useRef<HTMLSpanElement>(null);
const ref = useRef<HTMLInputElement>(null);
const [focused, setFocused] = useState(false);

const handleFocus = () => {
ref.current?.focus();
// select all text in the span... this is a hacky way to do it and not sure if it's the best way
document.execCommand("selectAll", false, undefined);
ref?.current?.focus();
};

return (
<div>
<Title className="text-base text-sauced-orange">New List</Title>
<div className="flex items-center gap-3">
{/* Using a span to mimic an input because native inputs can't auto grow in width relative to it's content
** https://css-tricks.com/auto-growing-inputs-textareas/
*/}
<span
ref={ref}
onInput={(e) => {
onEditTitle && onEditTitle(e.currentTarget.textContent ?? "");
}}
suppressContentEditableWarning
className={clsx("text-3xl auto-grow-input text-gray-300 focus:outline-none cursor-text")}
role="text-box"
contentEditable
>
{title}
</span>
<button onClick={handleFocus} type="button">
<HiPencil className="text-xl" />
</button>
<div className="relative text-3xl w-max">
<input
ref={ref}
onChange={(e) => {
onEditTitle?.(e.target.value);
}}
onBlur={() => {
setFocused(false);
}}
onFocus={(e) => {
setFocused(true);
e.target.select();
}}
autoFocus
value={title}
type="text"
placeholder="List Name"
className={clsx(
"text-3xl w-40 bg-transparent text-light-slate-12 focus:outline-none cursor-text",
!focused && "!text-white"
)}
/>
<span className={clsx("absolute left-0 w-max", focused && "invisible")}>
{title}

{title && title.length > 0 && (
<button onClick={handleFocus} type="button">
<HiPencil className="ml-2 text-xl" />
</button>
)}
</span>
</div>
{!focused && !title && (
<button onClick={handleFocus} type="button">
<HiPencil className="ml-2 text-xl" />
</button>
)}
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion components/atoms/ToggleSwitch/toggle-switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const ToggleSwitch = ({
classNames ?? classNames,
checked && "!bg-light-orange-10 justify-end",
"flex rounded-2xl p-[2px] transition overflow-hidden bg-light-slate-8",
size === "lg" ? "w-14 h-[30px]" : size === "base" ? "w-11 h-6" : size === "sm" ? "w-7 h-4" : ""
size === "lg" ? "w-14 h-[30px]" : size === "base" ? "w-10 h-5" : size === "sm" ? "w-7 h-4" : ""
)}
>
<Switch.Thumb className={clsx("bg-white block rounded-2xl h-full w-1/2")} />
Expand Down
27 changes: 12 additions & 15 deletions components/molecules/ComponentDateFilter/component-date-filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,18 @@ const ComponentDateFilter = ({ setRangeFilter, defaultRange }: ComponentDateFilt
};

return (
<div className="flex text-sm gap-4 items-center">
<span>Date filter:</span>
<div className="flex items-center">
{dates.map((range, index) => (
<div
onClick={() => handleFilterClick(range)}
className={`px-2 py-1 rounded-lg cursor-pointer transition text-light-slate-9 ${
activeFilter === range && "border text-light-slate-12 border-light-orange-10"
}`}
key={index}
>
{rangeFormatter(range)}
</div>
))}
</div>
<div className="flex items-center text-sm bg-white rounded-lg">
{dates.map((range, index) => (
<div
onClick={() => handleFilterClick(range)}
className={`px-4 py-1.5 rounded-lg cursor-pointer transition text-light-slate-9 ${
activeFilter === range && "border text-light-slate-12 bg-light-slate-5"
}`}
key={index}
>
{rangeFormatter(range)}
</div>
))}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@ import clsx from "clsx";
import React from "react";
import TableTitle from "components/atoms/TableTitle/table-title";
import { classNames } from "components/organisms/RepositoriesTable/repositories-table";
import Checkbox from "components/atoms/Checkbox/checkbox";

const ContributorListTableHeaders = () => {
interface ContributorListTableHeadersProps {
selected?: boolean;
handleOnSelectAllContributor?: (contributor: any) => void;
}

const ContributorListTableHeaders = ({ selected, handleOnSelectAllContributor }: ContributorListTableHeadersProps) => {
return (
<div className="mt-4">
{/* Mobile */}
<div className="flex justify-between gap-2 px-6 py-4 rounded-t-lg md:hidden bg-light-slate-3">
<div className="w-[58%]">
<div className="flex justify-between gap-2 px-2 py-4 rounded-t-lg md:hidden bg-light-slate-3">
{handleOnSelectAllContributor && (
<Checkbox
checked={selected ? true : false}
onCheckedChange={handleOnSelectAllContributor}
className={`${"border-orange-500 hover:bg-orange-600"}`}
/>
)}
<div className="w-[50%]">
<TableTitle>Contributor</TableTitle>
</div>
<div className="flex-1 w-[42%]">
Expand All @@ -17,23 +30,30 @@ const ContributorListTableHeaders = () => {
</div>
{/* Desktop */}
<div className="hidden gap-6 px-6 py-4 border rounded-t-lg md:flex bg-light-slate-3">
<div className={clsx("flex-1 lg:min-w-[250px] flex justify-center")}>
{handleOnSelectAllContributor && (
<Checkbox
checked={selected ? true : false}
onCheckedChange={handleOnSelectAllContributor}
className={`${"border-orange-500 hover:bg-orange-600"}`}
/>
)}
<div className={clsx("flex-1 lg:min-w-[12.5rem] flex justify-center")}>
<TableTitle>Contributor</TableTitle>
</div>
<div className={clsx(" flex-1 lg:max-w-[100px] flex justify-center ")}>
<div className={clsx(" flex-1 lg:max-w-[6.25rem] flex justify-center ")}>
<TableTitle>Act</TableTitle>
</div>
<div className={clsx("flex-1 lg:max-w-[100px] ")}>
<div className={clsx("flex-1 lg:max-w-[6.25rem] ")}>
<TableTitle>Repositories</TableTitle>
</div>
<div className={clsx("flex-1 lg:max-w-[130px] ")}>
<div className={clsx("flex-1 lg:max-w-[8.1rem] ")}>
<TableTitle>Last Contributed</TableTitle>
</div>
<div className={clsx(" flex flex-1 justify-center max-w-[120px]")}>
<div className={clsx(" flex flex-1 justify-center max-w-[7.5rem]")}>
<TableTitle>Language</TableTitle>
</div>

<div className={clsx("flex-1 hidden lg:flex justify-center lg:max-w-[80px]")}>
<div className={clsx("flex-1 hidden lg:flex justify-center lg:max-w-[5rem]")}>
<TableTitle>Time zone</TableTitle>
</div>
<div className={clsx("flex-1 hidden lg:flex lg:max-w-fit")}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ import { classNames } from "components/organisms/RepositoriesTable/repositories-
import useContributorPullRequests from "lib/hooks/api/useContributorPullRequests";
import useRepoList from "lib/hooks/useRepoList";
import { useFetchUser } from "lib/hooks/useFetchUser";
import Checkbox from "components/atoms/Checkbox/checkbox";
import { getActivity } from "../RepoRow/repo-row";
import DevProfile from "../DevProfile/dev-profile";

interface ContributorListTableRow {
contributor: DbPRContributor;
topic: string;
selected?: boolean;
handleOnSelectContributor?: (state: boolean, contributor: DbPRContributor) => void;
}

function getLastContributionDate(contributions: DbRepoPR[]) {
Expand All @@ -39,7 +42,12 @@ function getLastContributedRepo(pullRequests: DbRepoPR[]) {

return sortedPullRequests[0].full_name;
}
const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow) => {
const ContributorListTableRow = ({
contributor,
topic,
selected,
handleOnSelectContributor,
}: ContributorListTableRow) => {
const [tableOpen, setTableOpen] = useState(false);

const { data: user } = useFetchUser(contributor.author_login);
Expand All @@ -62,9 +70,18 @@ const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow
return (
<>
{/* Mobile version */}
<div className="px-5 py-2 overflow-hidden odd:bg-white md:hidden even:bg-light-slate-2">
<div className="px-2 py-2 overflow-hidden md:px-5 odd:bg-white md:hidden even:bg-light-slate-2">
<div className="flex items-center gap-x-3 text-light-slate-12">
<div className="w-[66%]">
{handleOnSelectContributor && (
<Checkbox
checked={selected ? true : false}
disabled={!user}
title={!user ? "Connect to GitHub" : ""}
onCheckedChange={(state) => handleOnSelectContributor?.(state as boolean, contributor)}
className={`${user && "border-orange-500 hover:bg-orange-600"}`}
/>
)}
<div className="w-[68%]">
<DevProfile company={user?.company || getLastContributedRepo(data)} username={contributor.author_login} />
</div>
<div className="w-[34%] text-normal text-light-slate-11 h-full">
Expand Down Expand Up @@ -121,34 +138,36 @@ const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow
{/* Desktop Version */}

<div className={`${classNames.row} !gap-6 text-light-slate-11`}>
{/* <Checkbox
checked={true}
onCheckedChange={() => console.log("yeah")}
disabled={!user}
title={!user ? "Connect to GitHub" : ""}
className={`${user && "border-orange-500 hover:bg-orange-600"}`}
/> */}
{handleOnSelectContributor && (
<Checkbox
checked={selected ? true : false}
disabled={!user}
title={!user ? "Connect to GitHub" : ""}
onCheckedChange={(state) => handleOnSelectContributor?.(state as boolean, contributor)}
className={`${user && "border-orange-500 hover:bg-orange-600"}`}
/>
)}

{/* Column: Contributors */}
<div className={clsx("flex-1 lg:min-w-[250px] overflow-hidden")}>
<div className={clsx("flex-1 lg:min-w-[12.5rem] overflow-hidden")}>
<DevProfile company={user?.company || getLastContributedRepo(data)} username={contributor.author_login} />
</div>

{/* Column: Act */}
<div className={clsx("flex-1 flex lg:max-w-[100px] w-fit justify-center")}>
<div className={clsx("flex-1 flex lg:max-w-[6.25rem] w-fit justify-center")}>
{getActivity(totalPrs, false)}
</div>

{/* Column Repositories */}
<div className={clsx("flex-1 lg:max-w-[100px] flex justify-center ")}>{repoList.length}</div>
<div className={clsx("flex-1 lg:max-w-[6.25rem] flex justify-center ")}>{repoList.length}</div>

{/* Column: Last Contribution */}
<div className={clsx("flex-1 lg:max-w-[130px] flex text-light-slate-11 justify-center ")}>
<div className="flex">{<p>{getLastContributionDate(mergedPrs)}</p>}</div>
</div>

{/* Column: Language */}
<div className={clsx("flex-1 hidden lg:max-w-[120px] justify-center lg:flex")}>
<div className={clsx("flex-1 hidden lg:max-w-[7.5rem] justify-center lg:flex")}>
{contributorLanguageList.length > 0 ? (
<p>
{contributorLanguageList[0]}
Expand All @@ -160,16 +179,16 @@ const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow
</div>

{/* Column: Time Zone */}
<div className={clsx("flex-1 hidden lg:max-w-[80px] text-light-slate-11 justify-center lg:flex ")}>
<div className={clsx("flex-1 hidden lg:max-w-[5rem] text-light-slate-11 justify-center lg:flex ")}>
<div className="flex gap-x-3">{user && user.timezone ? <p>{user.timezone}</p> : "-"}</div>
</div>

{/* Column: Contributions */}
<div className={clsx("flex-1 hidden justify-center lg:flex lg:max-w-[120px]")}>
<div className={clsx("flex-1 hidden justify-center lg:flex lg:max-w-[7.5rem]")}>
<p>{mergedPrs.length}</p>
</div>
{/* Column Last 30 Days */}
<div className={clsx("flex-1 lg:min-w-[150px] hidden lg:flex justify-center")}>
<div className={clsx("flex-1 lg:min-w-[9.37rem] hidden lg:flex justify-center")}>
{last30days ? <Sparkline data={last30days} width="100%" height={54} /> : "-"}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/molecules/DevProfile/dev-profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const DevProfile = ({ username, company }: DevProfileProps) => {
</div>
{/* Desktop */}
<div className="hidden rounded-full md:flex">
<Avatar className="" size={60} isCircle avatarURL={getAvatarByUsername(username)} />
<Avatar className="" size={45} isCircle avatarURL={getAvatarByUsername(username)} />
</div>
<div>
<h1 className="text-light-slate-12">
Expand Down
Loading