www: add features for privacy and browsing

This commit is contained in:
2023-10-13 09:58:16 +02:00
committed by Mathieu Virbel
parent a3e9683f1e
commit 168e4d6fa4
5 changed files with 208 additions and 7 deletions

89
www/app/browse/page.tsx Normal file
View File

@@ -0,0 +1,89 @@
"use client";
import React, { useState, useEffect } from "react";
import getApi from "../lib/getApi";
import {
PageGetTranscript,
GetTranscript,
GetTranscriptFromJSON,
} from "../api";
import { Title } from "../lib/textComponents";
import Pagination from "./pagination";
import Link from "next/link";
export default function TranscriptBrowser() {
const api = getApi();
const [results, setResults] = useState<PageGetTranscript | null>(null);
const [page, setPage] = useState<number>(1);
useEffect(() => {
api.v1TranscriptsList({ page }).then((response) => {
// issue with API layer, conversion for items is not happening
response.items = response.items.map((item) =>
GetTranscriptFromJSON(item),
);
setResults(response);
});
}, [page]);
return (
<div>
{/*
<div className="flex flex-row gap-2">
<input className="text-sm p-2 w-80 ring-1 ring-slate-900/10 shadow-sm rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 caret-blue-500" placeholder="Search" />
</div>
*/}
<div className="flex flex-row gap-2 items-center">
<Title className="mb-5 mt-5 flex-1">Past transcripts</Title>
<Pagination
page={page}
setPage={setPage}
total={results?.total || 0}
size={results?.size || 0}
/>
</div>
<div /** center and max 900px wide */ className="mx-auto max-w-[900px]">
<div className="grid grid-cols-1 gap-2 lg:gap-4 h-full">
{results?.items.map((item: GetTranscript) => (
<div
key={item.id}
className="flex flex-col bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4"
>
<div className="flex flex-col">
<div className="flex flex-row gap-2 items-start">
<Link
href={`/transcripts/${item.id}`}
className="text-1xl font-semibold flex-1 pl-0 hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
{item.title || item.name}
</Link>
{item.locked ? (
<div className="inline-block bg-red-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
Locked
</div>
) : (
<></>
)}
{item.sourceLanguage ? (
<div className="inline-block bg-blue-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
{item.sourceLanguage}
</div>
) : (
<></>
)}
</div>
<div className="text-xs text-gray-700">
{new Date(item.createdAt).toLocaleDateString("en-US")}
</div>
<div className="text-sm">{item.shortSummary}</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,75 @@
type PaginationProps = {
page: number;
setPage: (page: number) => void;
total: number;
size: number;
};
export default function Pagination(props: PaginationProps) {
const { page, setPage, total, size } = props;
const totalPages = Math.ceil(total / size);
const pageNumbers = Array.from(
{ length: totalPages },
(_, i) => i + 1,
).filter((pageNumber) => {
if (totalPages <= 3) {
// If there are 3 or fewer total pages, show all pages.
return true;
} else if (page <= 2) {
// For the first two pages, show the first 3 pages.
return pageNumber <= 3;
} else if (page >= totalPages - 1) {
// For the last two pages, show the last 3 pages.
return pageNumber >= totalPages - 2;
} else {
// For all other cases, show 3 pages centered around the current page.
return pageNumber >= page - 1 && pageNumber <= page + 1;
}
});
const canGoPrevious = page > 1;
const canGoNext = page < totalPages;
const handlePageChange = (newPage: number) => {
if (newPage >= 1 && newPage <= totalPages) {
setPage(newPage);
}
};
return (
<div className="flex justify-center space-x-4 my-4">
<button
className={`w-10 h-10 rounded-full p-2 border border-gray-300 rounded-full disabled:bg-white ${
canGoPrevious ? "text-gray-500" : "text-gray-300"
}`}
onClick={() => handlePageChange(page - 1)}
disabled={!canGoPrevious}
>
<i className="fa fa-chevron-left">&lt;</i>
</button>
{pageNumbers.map((pageNumber) => (
<button
key={pageNumber}
className={`w-10 h-10 rounded-full p-2 border rounded-full ${
page === pageNumber ? "border-gray-600" : "border-gray-300"
} rounded`}
onClick={() => handlePageChange(pageNumber)}
>
{pageNumber}
</button>
))}
<button
className={`w-10 h-10 rounded-full p-2 border border-gray-300 rounded-full disabled:bg-white ${
canGoNext ? "text-gray-500" : "text-gray-300"
}`}
onClick={() => handlePageChange(page + 1)}
disabled={!canGoNext}
>
<i className="fa fa-chevron-right">&gt;</i>
</button>
</div>
);
}

View File

@@ -9,6 +9,7 @@ import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import About from "./(aboutAndPrivacy)/about"; import About from "./(aboutAndPrivacy)/about";
import Privacy from "./(aboutAndPrivacy)/privacy"; import Privacy from "./(aboutAndPrivacy)/privacy";
import { featPrivacy } from "./lib/utils";
const poppins = Poppins({ subsets: ["latin"], weight: ["200", "400", "600"] }); const poppins = Poppins({ subsets: ["latin"], weight: ["200", "400", "600"] });
@@ -93,9 +94,29 @@ export default function RootLayout({ children }) {
</Link> </Link>
<div> <div>
{/* Text link on the right */} {/* Text link on the right */}
<Link
href="/transcripts/new"
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
Create
</Link>
&nbsp;·&nbsp;
<Link
href="/browse"
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
Browse
</Link>
&nbsp;·&nbsp;
<About buttonText="About" /> <About buttonText="About" />
{featPrivacy() ? (
<>
&nbsp;·&nbsp; &nbsp;·&nbsp;
<Privacy buttonText="Privacy" /> <Privacy buttonText="Privacy" />
</>
) : (
<></>
)}
</div> </div>
</header> </header>

View File

@@ -1,3 +1,11 @@
export function isDevelopment() { export function isDevelopment() {
return process.env.NEXT_PUBLIC_ENV === "development"; return process.env.NEXT_PUBLIC_ENV === "development";
} }
export function featPrivacy() {
return process.env.NEXT_PUBLIC_FEAT_PRIVACY === "1";
}
export function featBrowse() {
return process.env.NEXT_PUBLIC_FEAT_BROWSE === "1";
}

View File

@@ -1,4 +1,5 @@
import React, { useState, useRef, useEffect, use } from "react"; import React, { useState, useRef, useEffect, use } from "react";
import { featPrivacy } from "../lib/utils";
const ShareLink = () => { const ShareLink = () => {
const [isCopied, setIsCopied] = useState(false); const [isCopied, setIsCopied] = useState(false);
@@ -27,11 +28,18 @@ const ShareLink = () => {
className="p-2 md:p-4 rounded" className="p-2 md:p-4 rounded"
style={{ background: "rgba(96, 165, 250, 0.2)" }} style={{ background: "rgba(96, 165, 250, 0.2)" }}
> >
{featPrivacy() ? (
<p className="text-sm mb-2"> <p className="text-sm mb-2">
You can share this link with others. Anyone with the link will have You can share this link with others. Anyone with the link will have
access to the page, including the full audio recording, for the next 7 access to the page, including the full audio recording, for the next 7
days. days.
</p> </p>
) : (
<p className="text-sm mb-2">
You can share this link with others. Anyone with the link will have
access to the page, including the full audio recording.
</p>
)}
<div className="flex items-center"> <div className="flex items-center">
<input <input
type="text" type="text"