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 */}
<About buttonText="About" /> <Link
href="/transcripts/new"
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
Create
</Link>
&nbsp;·&nbsp; &nbsp;·&nbsp;
<Privacy buttonText="Privacy" /> <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" />
{featPrivacy() ? (
<>
&nbsp;·&nbsp;
<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)" }}
> >
<p className="text-sm mb-2"> {featPrivacy() ? (
You can share this link with others. Anyone with the link will have <p className="text-sm mb-2">
access to the page, including the full audio recording, for the next 7 You can share this link with others. Anyone with the link will have
days. access to the page, including the full audio recording, for the next 7
</p> days.
</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"