feat: better performance
This commit is contained in:
parent
1ae0638d3c
commit
7a9382ddf1
|
|
@ -1,5 +1,4 @@
|
|||
import {AnalyticsComponent} from "@gitroom/frontend/components/analytics/analytics.component";
|
||||
import {internalFetch} from "@gitroom/helpers/utils/internal.fetch";
|
||||
import {Metadata} from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
|
@ -8,14 +7,7 @@ export const metadata: Metadata = {
|
|||
}
|
||||
|
||||
export default async function Index() {
|
||||
const analytics = await (await internalFetch('/analytics')).json();
|
||||
const trending = await (await internalFetch('/analytics/trending')).json();
|
||||
const stars = await (await internalFetch('/analytics/stars', {
|
||||
body: JSON.stringify({page: 1}),
|
||||
method: 'POST'
|
||||
})).json();
|
||||
|
||||
return (
|
||||
<AnalyticsComponent list={analytics} trending={trending} stars={stars.stars} />
|
||||
<AnalyticsComponent />
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { internalFetch } from '@gitroom/helpers/utils/internal.fetch';
|
||||
import { BillingComponent } from '@gitroom/frontend/components/billing/billing.component';
|
||||
import { Metadata } from 'next';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Gitroom Billing',
|
||||
|
|
@ -9,13 +7,5 @@ export const metadata: Metadata = {
|
|||
};
|
||||
|
||||
export default async function Page() {
|
||||
const tiers = await (await internalFetch('/user/subscription/tiers')).json();
|
||||
if (tiers?.statusCode === 402) {
|
||||
return redirect('/');
|
||||
}
|
||||
const { subscription } = await (
|
||||
await internalFetch('/user/subscription')
|
||||
).json();
|
||||
|
||||
return <BillingComponent subscription={subscription} tiers={tiers} />;
|
||||
return <BillingComponent />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import {LaunchesComponent} from "@gitroom/frontend/components/launches/launches.component";
|
||||
import {internalFetch} from "@gitroom/helpers/utils/internal.fetch";
|
||||
import {Metadata} from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
|
@ -8,8 +7,7 @@ export const metadata: Metadata = {
|
|||
}
|
||||
|
||||
export default async function Index() {
|
||||
const {integrations} = await (await internalFetch('/integrations/list')).json();
|
||||
return (
|
||||
<LaunchesComponent integrations={integrations} />
|
||||
<LaunchesComponent />
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingComponent />;
|
||||
}
|
||||
|
|
@ -22,16 +22,5 @@ export default async function Index({
|
|||
return redirect('/settings', RedirectType.replace);
|
||||
}
|
||||
|
||||
const { github } = await (await internalFetch('/settings/github')).json();
|
||||
if (!github) {
|
||||
return redirect('/');
|
||||
}
|
||||
const emptyOnes = github.find((p: { login: string }) => !p.login);
|
||||
const { organizations } = emptyOnes
|
||||
? await (
|
||||
await internalFetch(`/settings/organizations/${emptyOnes.id}`)
|
||||
).json()
|
||||
: { organizations: [] };
|
||||
|
||||
return <SettingsComponent github={github} organizations={organizations} />;
|
||||
return <SettingsComponent />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,105 +1,141 @@
|
|||
import {StarsAndForks} from "@gitroom/frontend/components/analytics/stars.and.forks";
|
||||
import {FC} from "react";
|
||||
import {StarsAndForksInterface} from "@gitroom/frontend/components/analytics/stars.and.forks.interface";
|
||||
import {StarsTableComponent} from "@gitroom/frontend/components/analytics/stars.table.component";
|
||||
'use client';
|
||||
|
||||
export const AnalyticsComponent: FC<StarsAndForksInterface> = (props) => {
|
||||
return (
|
||||
<div className="flex gap-[24px] flex-1">
|
||||
<div className="flex flex-col gap-[24px] flex-1">
|
||||
<StarsAndForks {...props} />
|
||||
<div className="flex flex-1 flex-col gap-[15px] min-h-[426px]">
|
||||
<h2 className="text-[24px]">Stars per day</h2>
|
||||
<div className="flex-1 bg-secondary">
|
||||
<StarsTableComponent stars={props.stars} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/*<div className="w-[318px] bg-third mt-[-44px] p-[16px]">*/}
|
||||
{/* <h2 className="text-[20px]">News Feed</h2>*/}
|
||||
{/* <div className="my-[30px] flex h-[32px]">*/}
|
||||
{/* <div className="flex-1 bg-forth flex justify-center items-center">*/}
|
||||
{/* Global*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="flex-1 bg-primary flex justify-center items-center">*/}
|
||||
{/* My Feed*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <div className="w-full flex-col justify-start items-start gap-4 inline-flex">*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
import { StarsAndForks } from '@gitroom/frontend/components/analytics/stars.and.forks';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { StarsTableComponent } from '@gitroom/frontend/components/analytics/stars.table.component';
|
||||
import useSWR from 'swr';
|
||||
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
|
||||
import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
|
||||
|
||||
export const AnalyticsComponent: FC = () => {
|
||||
const fetch = useFetch();
|
||||
|
||||
const load = useCallback(async (path: string) => {
|
||||
return await (await fetch(path)).json();
|
||||
}, []);
|
||||
|
||||
const starsCallback = useCallback(async (path: string) => {
|
||||
return await (
|
||||
await fetch(path, {
|
||||
body: JSON.stringify({ page: 1 }),
|
||||
method: 'POST',
|
||||
})
|
||||
).json();
|
||||
}, []);
|
||||
|
||||
const { isLoading: isLoadingAnalytics, data: analytics } = useSWR(
|
||||
'/analytics',
|
||||
load
|
||||
);
|
||||
const { isLoading: isLoadingTrending, data: trending } = useSWR(
|
||||
'/analytics/trending',
|
||||
load
|
||||
);
|
||||
const { isLoading: isLoadingStars, data: stars } = useSWR(
|
||||
'/analytics/stars',
|
||||
starsCallback
|
||||
);
|
||||
|
||||
if (isLoadingAnalytics || isLoadingTrending || isLoadingStars) {
|
||||
return <LoadingComponent />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex gap-[24px] flex-1">
|
||||
<div className="flex flex-col gap-[24px] flex-1">
|
||||
<StarsAndForks list={analytics} stars={stars.stars} trending={trending} />
|
||||
<div className="flex flex-1 flex-col gap-[15px] min-h-[426px]">
|
||||
<h2 className="text-[24px]">Stars per day</h2>
|
||||
<div className="flex-1 bg-secondary">
|
||||
<StarsTableComponent stars={stars.stars} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
{/*<div className="w-[318px] bg-third mt-[-44px] p-[16px]">*/}
|
||||
{/* <h2 className="text-[20px]">News Feed</h2>*/}
|
||||
{/* <div className="my-[30px] flex h-[32px]">*/}
|
||||
{/* <div className="flex-1 bg-forth flex justify-center items-center">*/}
|
||||
{/* Global*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="flex-1 bg-primary flex justify-center items-center">*/}
|
||||
{/* My Feed*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <div className="w-full flex-col justify-start items-start gap-4 inline-flex">*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch justify-start items-start gap-2.5 inline-flex pb-[16.5px] border-b-[1px] border-[#28344F]">*/}
|
||||
{/* <img className="w-8 h-8 rounded-full" src="https://via.placeholder.com/32x32"/>*/}
|
||||
{/* <div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">*/}
|
||||
{/* <div className="justify-center items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-white text-sm font-medium leading-tight">Nevo David</div>*/}
|
||||
{/* <div className="text-neutral-500 text-[10px] font-normal uppercase tracking-wide">05/06/2024</div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="self-stretch text-neutral-400 text-xs font-normal">O atual sistema político precisa mudar para valorizar o trabalho e garantir igualdade de oportunidad</div>*/}
|
||||
{/* <div className="self-stretch justify-start items-center gap-1 inline-flex">*/}
|
||||
{/* <div className="text-[#E4B895] text-xs font-normal">See Tweet</div>*/}
|
||||
{/* <div className="w-4 h-4 relative"/>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,65 +1,123 @@
|
|||
import {FC} from "react";
|
||||
import {StarsAndForksInterface} from "@gitroom/frontend/components/analytics/stars.and.forks.interface";
|
||||
import {Chart} from "@gitroom/frontend/components/analytics/chart";
|
||||
import Image from "next/image";
|
||||
import {UtcToLocalDateRender} from "../../../../../libraries/react-shared-libraries/src/helpers/utc.date.render";
|
||||
import clsx from "clsx";
|
||||
import { FC } from 'react';
|
||||
import { StarsAndForksInterface } from '@gitroom/frontend/components/analytics/stars.and.forks.interface';
|
||||
import { Chart } from '@gitroom/frontend/components/analytics/chart';
|
||||
import Image from 'next/image';
|
||||
import { UtcToLocalDateRender } from '../../../../../libraries/react-shared-libraries/src/helpers/utc.date.render';
|
||||
import clsx from 'clsx';
|
||||
|
||||
export const StarsAndForks: FC<StarsAndForksInterface> = (props) => {
|
||||
const {list} = props;
|
||||
return (
|
||||
<>
|
||||
{list.map(item => (
|
||||
<div className="flex gap-[24px] h-[272px]" key={item.login}>
|
||||
{[1,2].map(p => (
|
||||
<div key={p} className="flex-1 bg-secondary py-[10px] px-[16px] flex flex-col">
|
||||
<div className="flex items-center gap-[14px]">
|
||||
<div>
|
||||
<Image src="/icons/star-circle.svg" alt="Stars" width={40} height={40}/>
|
||||
</div>
|
||||
<div className="text-[20px]">
|
||||
{item.login.split('/')[1].split('').map(((char, index) => index === 0 ? char.toUpperCase() : char)).join('')} {p === 1 ? 'Stars' : 'Forks'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 relative">
|
||||
<div className="absolute w-full h-full left-0 top-0">
|
||||
{item.stars.length ? <Chart list={item.stars}/> : <div className="w-full h-full flex items-center justify-center text-3xl">Processing stars...</div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-[50px] leading-[60px]">
|
||||
{item?.stars[item.stars.length - 1]?.totalStars}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
const { list } = props;
|
||||
return (
|
||||
<>
|
||||
{list.map((item) => (
|
||||
<div className="flex gap-[24px] h-[272px]" key={item.login}>
|
||||
{[1, 2].map((p) => (
|
||||
<div
|
||||
key={p}
|
||||
className="flex-1 bg-secondary py-[10px] px-[16px] flex flex-col"
|
||||
>
|
||||
<div className="flex items-center gap-[14px]">
|
||||
<div>
|
||||
<Image
|
||||
src="/icons/star-circle.svg"
|
||||
alt="Stars"
|
||||
width={40}
|
||||
height={40}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<div className="flex gap-[24px]">
|
||||
{[0, 1].map( p => (
|
||||
<div key={p} className="flex-1 bg-secondary py-[24px] px-[16px] gap-[16px] flex flex-col">
|
||||
<div className="flex items-center gap-[14px]">
|
||||
<div>
|
||||
<Image src="/icons/trending.svg" width={36} height={36} alt="Trending" />
|
||||
</div>
|
||||
<div className="text-[20px]">
|
||||
{p === 0 ? 'Last Github Trending' : 'Next Predicted GitHub Trending'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-[2px] h-[30px] bg-[#8B90FF] mr-[16px]"></div>
|
||||
<div className="text-[24px] flex-1">
|
||||
<UtcToLocalDateRender date={p === 0 ? props.trending.last : props.trending.predictions} format="dddd"/>
|
||||
</div>
|
||||
<div className={clsx("text-[24px]", p === 0 ? 'text-[#B7C1FF]' : 'text-[#FFAC30]')}>
|
||||
<UtcToLocalDateRender date={p === 0 ? props.trending.last : props.trending.predictions} format="DD MMM YYYY"/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="rounded-full bg-[#576A9A] w-[5px] h-[5px] mx-[8px]"/>
|
||||
</div>
|
||||
<div className={clsx("text-[24px]", p === 0 ? 'text-[#B7C1FF]' : 'text-[#FFAC30]')}>
|
||||
<UtcToLocalDateRender date={p === 0 ? props.trending.last : props.trending.predictions} format="HH:mm"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>))}
|
||||
<div className="text-[20px]">
|
||||
{item.login
|
||||
.split('/')[1]
|
||||
.split('')
|
||||
.map((char, index) =>
|
||||
index === 0 ? char.toUpperCase() : char
|
||||
)
|
||||
.join('')}{' '}
|
||||
{p === 1 ? 'Stars' : 'Forks'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 relative">
|
||||
<div className="absolute w-full h-full left-0 top-0">
|
||||
{item.stars.length ? (
|
||||
<Chart list={item.stars} />
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center text-3xl">
|
||||
Processing stars...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-[50px] leading-[60px]">
|
||||
{item?.stars[item.stars.length - 1]?.totalStars}
|
||||
</div>
|
||||
</div>
|
||||
</>);
|
||||
}
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
<div className="flex gap-[24px]">
|
||||
{[0, 1].map((p) => (
|
||||
<div
|
||||
key={p}
|
||||
className="flex-1 bg-secondary py-[24px] px-[16px] gap-[16px] flex flex-col"
|
||||
>
|
||||
<div className="flex items-center gap-[14px]">
|
||||
<div>
|
||||
<Image
|
||||
src="/icons/trending.svg"
|
||||
width={36}
|
||||
height={36}
|
||||
alt="Trending"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-[20px]">
|
||||
{p === 0
|
||||
? 'Last Github Trending'
|
||||
: 'Next Predicted GitHub Trending'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-[2px] h-[30px] bg-[#8B90FF] mr-[16px]"></div>
|
||||
<div className="text-[24px] flex-1">
|
||||
<UtcToLocalDateRender
|
||||
date={
|
||||
p === 0 ? props.trending.last : props.trending.predictions
|
||||
}
|
||||
format="dddd"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'text-[24px]',
|
||||
p === 0 ? 'text-[#B7C1FF]' : 'text-[#FFAC30]'
|
||||
)}
|
||||
>
|
||||
<UtcToLocalDateRender
|
||||
date={
|
||||
p === 0 ? props.trending.last : props.trending.predictions
|
||||
}
|
||||
format="DD MMM YYYY"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="rounded-full bg-[#576A9A] w-[5px] h-[5px] mx-[8px]" />
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'text-[24px]',
|
||||
p === 0 ? 'text-[#B7C1FF]' : 'text-[#FFAC30]'
|
||||
)}
|
||||
>
|
||||
<UtcToLocalDateRender
|
||||
date={
|
||||
p === 0 ? props.trending.last : props.trending.predictions
|
||||
}
|
||||
format="HH:mm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
import { FC } from 'react';
|
||||
import { Subscription } from '@prisma/client';
|
||||
import {
|
||||
NoBillingComponent,
|
||||
Tiers,
|
||||
} from '@gitroom/frontend/components/billing/no.billing.component';
|
||||
"use client";
|
||||
|
||||
export const BillingComponent: FC<{
|
||||
subscription?: Subscription;
|
||||
tiers: Tiers;
|
||||
}> = (props) => {
|
||||
const { subscription, tiers } = props;
|
||||
return <NoBillingComponent tiers={tiers} sub={subscription} />;
|
||||
import { useCallback } from 'react';
|
||||
import { NoBillingComponent } from '@gitroom/frontend/components/billing/no.billing.component';
|
||||
import useSWR from 'swr';
|
||||
import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
|
||||
import {useFetch} from "@gitroom/helpers/utils/custom.fetch";
|
||||
|
||||
export const BillingComponent = () => {
|
||||
const fetch = useFetch();
|
||||
const load = useCallback(async (path: string) => {
|
||||
return await (await fetch(path)).json();
|
||||
}, []);
|
||||
|
||||
const { isLoading: isLoadingTier, data: tiers } = useSWR(
|
||||
'/user/subscription/tiers',
|
||||
load
|
||||
);
|
||||
const { isLoading: isLoadingSubscription, data: subscription } = useSWR(
|
||||
'/user/subscription',
|
||||
load
|
||||
);
|
||||
|
||||
if (isLoadingSubscription || isLoadingTier) {
|
||||
return <LoadingComponent />;
|
||||
}
|
||||
|
||||
return <NoBillingComponent tiers={tiers} sub={subscription?.subscription} />;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,18 +1,30 @@
|
|||
'use client';
|
||||
|
||||
import { AddProviderButton } from '@gitroom/frontend/components/launches/add.provider.component';
|
||||
import { FC, useMemo } from 'react';
|
||||
import { FC, useCallback, useMemo } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { orderBy } from 'lodash';
|
||||
import { Calendar } from '@gitroom/frontend/components/launches/calendar';
|
||||
import {
|
||||
CalendarWeekProvider,
|
||||
Integrations,
|
||||
} from '@gitroom/frontend/components/launches/calendar.context';
|
||||
import { Filters } from '@gitroom/frontend/components/launches/filters';
|
||||
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
|
||||
import useSWR from 'swr';
|
||||
|
||||
export const LaunchesComponent: FC<{
|
||||
integrations: Integrations[];
|
||||
}> = (props) => {
|
||||
const { integrations } = props;
|
||||
export const LaunchesComponent = () => {
|
||||
const fetch = useFetch();
|
||||
const load = useCallback(async (path: string) => {
|
||||
return (await (await fetch(path)).json()).integrations;
|
||||
}, []);
|
||||
|
||||
const { data: integrations } = useSWR(
|
||||
'/integrations/list',
|
||||
load,
|
||||
{
|
||||
fallbackData: [],
|
||||
}
|
||||
);
|
||||
|
||||
const sortedIntegrations = useMemo(() => {
|
||||
return orderBy(integrations, ['type', 'identifier'], ['desc', 'asc']);
|
||||
|
|
@ -22,9 +34,7 @@ export const LaunchesComponent: FC<{
|
|||
<CalendarWeekProvider integrations={sortedIntegrations}>
|
||||
<div className="flex flex-1 flex-col">
|
||||
<div className="flex flex-1 relative">
|
||||
<div
|
||||
className="absolute w-full h-full flex flex-1 gap-[30px] overflow-hidden overflow-y-scroll scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary"
|
||||
>
|
||||
<div className="absolute w-full h-full flex flex-1 gap-[30px] overflow-hidden overflow-y-scroll scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary">
|
||||
<div className="w-[220px] bg-third p-[16px] flex flex-col gap-[24px] sticky top-0">
|
||||
<h2 className="text-[20px]">Channels</h2>
|
||||
<div className="gap-[16px] flex flex-col">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { ReactNode } from 'react';
|
||||
'use client';
|
||||
|
||||
import { ReactNode, useCallback } from 'react';
|
||||
import { Title } from '@gitroom/frontend/components/layout/title';
|
||||
import { headers } from 'next/headers';
|
||||
import { ContextWrapper } from '@gitroom/frontend/components/layout/user.context';
|
||||
|
|
@ -10,11 +12,22 @@ import Image from 'next/image';
|
|||
import { Toaster } from '@gitroom/react/toaster/toaster';
|
||||
import { ShowPostSelector } from '@gitroom/frontend/components/post-url-selector/post.url.selector';
|
||||
import { OrganizationSelector } from '@gitroom/frontend/components/layout/organization.selector';
|
||||
import NotificationComponent from "@gitroom/frontend/components/notifications/notification.component";
|
||||
import Link from "next/link";
|
||||
import NotificationComponent from '@gitroom/frontend/components/notifications/notification.component';
|
||||
import Link from 'next/link';
|
||||
import useSWR from 'swr';
|
||||
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
|
||||
|
||||
export const LayoutSettings = ({ children }: { children: ReactNode }) => {
|
||||
const user = JSON.parse(headers().get('user')!);
|
||||
const fetch = useFetch();
|
||||
const load = useCallback(async (path: string) => {
|
||||
return await (await fetch(path)).json();
|
||||
}, []);
|
||||
|
||||
const { data: user } = useSWR(
|
||||
'/user/self',
|
||||
load
|
||||
);
|
||||
|
||||
return (
|
||||
<ContextWrapper user={user}>
|
||||
<MantineWrapper>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
'use client';
|
||||
import ReactLoading from 'react-loading';
|
||||
|
||||
export const LoadingComponent = () => {
|
||||
return <div className="flex-1 flex justify-center pt-[100px]"><ReactLoading type="spin" color="#fff" width={100} height={100} /></div>;
|
||||
};
|
||||
|
|
@ -48,7 +48,7 @@ export const TopMenu: FC = () => {
|
|||
.map((item, index) => (
|
||||
<li key={item.name}>
|
||||
<Link
|
||||
prefetch={false}
|
||||
prefetch={true}
|
||||
href={item.path}
|
||||
className={clsx(
|
||||
'flex gap-2 items-center box',
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ export const ContextWrapper: FC<{
|
|||
};
|
||||
children: ReactNode;
|
||||
}> = ({ user, children }) => {
|
||||
const values = user ? { ...user, tier: pricing[user.tier] } : ({} as any);
|
||||
return (
|
||||
<UserContext.Provider value={{ ...user, tier: pricing[user.tier] }}>
|
||||
<UserContext.Provider value={values}>
|
||||
{children}
|
||||
</UserContext.Provider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,52 @@
|
|||
'use client';
|
||||
|
||||
import { Checkbox } from '@gitroom/react/form/checkbox';
|
||||
import { GithubComponent } from '@gitroom/frontend/components/settings/github.component';
|
||||
import { FC } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useUser } from '@gitroom/frontend/components/layout/user.context';
|
||||
import { TeamsComponent } from '@gitroom/frontend/components/settings/teams.component';
|
||||
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
|
||||
import useSWR from 'swr';
|
||||
import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
export const SettingsComponent: FC<{
|
||||
organizations: Array<{ login: string; id: string }>;
|
||||
github: Array<{ id: string; login: string }>;
|
||||
}> = (props) => {
|
||||
const { github, organizations } = props;
|
||||
export const SettingsComponent = () => {
|
||||
const user = useUser();
|
||||
const router = useRouter();
|
||||
|
||||
const fetch = useFetch();
|
||||
|
||||
const load = useCallback(async (path: string) => {
|
||||
const { github } = await (await fetch('/settings/github')).json();
|
||||
if (!github) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const emptyOnes = github.find((p: { login: string }) => !p.login);
|
||||
const { organizations } = emptyOnes
|
||||
? await (await fetch(`/settings/organizations/${emptyOnes.id}`)).json()
|
||||
: { organizations: [] };
|
||||
|
||||
return { github, organizations };
|
||||
}, []);
|
||||
|
||||
const { isLoading: isLoadingSettings, data: loadAll } = useSWR(
|
||||
'load-all',
|
||||
load
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoadingSettings && !loadAll) {
|
||||
router.push('/');
|
||||
}
|
||||
}, [loadAll, isLoadingSettings]);
|
||||
|
||||
if (isLoadingSettings) {
|
||||
return <LoadingComponent />;
|
||||
}
|
||||
|
||||
if (!loadAll) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-[68px]">
|
||||
|
|
@ -20,7 +55,10 @@ export const SettingsComponent: FC<{
|
|||
<div className="text-[#AAA] mt-[4px]">
|
||||
Connect your GitHub repository to receive updates and analytics
|
||||
</div>
|
||||
<GithubComponent github={github} organizations={organizations} />
|
||||
<GithubComponent
|
||||
github={loadAll.github}
|
||||
organizations={loadAll.organizations}
|
||||
/>
|
||||
{/*<div className="flex gap-[5px]">*/}
|
||||
{/* <div>*/}
|
||||
{/* <Checkbox disableForm={true} checked={true} name="Send Email" />*/}
|
||||
|
|
@ -28,7 +66,7 @@ export const SettingsComponent: FC<{
|
|||
{/* <div>Show news with everybody in Gitroom</div>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
{!!user?.tier.team_members && <TeamsComponent />}
|
||||
{!!user?.tier?.team_members && <TeamsComponent />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -84,27 +84,8 @@ export async function middleware(request: NextRequest) {
|
|||
return redirect;
|
||||
}
|
||||
|
||||
const userResponse = await fetchBackend('/user/self', {
|
||||
headers: {
|
||||
auth: authCookie?.value!,
|
||||
...(showorg?.value ? { showorg: showorg?.value! } : {}),
|
||||
},
|
||||
});
|
||||
return NextResponse.next();
|
||||
|
||||
if (userResponse.status === 401) {
|
||||
return NextResponse.redirect(new URL('/auth/logout', nextUrl.href));
|
||||
}
|
||||
|
||||
if ([200, 201].indexOf(userResponse.status) === -1) {
|
||||
return NextResponse.redirect(new URL('/err', nextUrl.href));
|
||||
}
|
||||
|
||||
const user = await userResponse.json();
|
||||
|
||||
const next = NextResponse.next();
|
||||
next.headers.set('user', JSON.stringify(user));
|
||||
|
||||
return next;
|
||||
} catch (err) {
|
||||
return NextResponse.redirect(new URL('/auth/logout', nextUrl.href));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue