add ExpireDateSelectMenu
This commit is contained in:
parent
a52dfcc7fb
commit
cc4f2ad4ee
5 changed files with 175 additions and 4 deletions
55
package-lock.json
generated
55
package-lock.json
generated
|
|
@ -13,6 +13,7 @@
|
||||||
"@aws-sdk/s3-request-presigner": "^3.310.0",
|
"@aws-sdk/s3-request-presigner": "^3.310.0",
|
||||||
"@headlessui/react": "^1.7.13",
|
"@headlessui/react": "^1.7.13",
|
||||||
"@next-auth/prisma-adapter": "^1.0.5",
|
"@next-auth/prisma-adapter": "^1.0.5",
|
||||||
|
"@popperjs/core": "^2.11.7",
|
||||||
"@prisma/client": "^4.11.0",
|
"@prisma/client": "^4.11.0",
|
||||||
"@tanstack/react-query": "^4.28.0",
|
"@tanstack/react-query": "^4.28.0",
|
||||||
"@trpc/client": "^10.18.0",
|
"@trpc/client": "^10.18.0",
|
||||||
|
|
@ -25,6 +26,7 @@
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-player": "^2.12.0",
|
"react-player": "^2.12.0",
|
||||||
|
"react-popper": "^2.3.0",
|
||||||
"superjson": "1.12.2",
|
"superjson": "1.12.2",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
|
|
@ -1754,6 +1756,15 @@
|
||||||
"url": "https://opencollective.com/unts"
|
"url": "https://opencollective.com/unts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@popperjs/core": {
|
||||||
|
"version": "2.11.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
|
||||||
|
"integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/popperjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@prisma/client": {
|
"node_modules/@prisma/client": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.12.0.tgz",
|
||||||
|
|
@ -5427,6 +5438,20 @@
|
||||||
"react": ">=16.6.0"
|
"react": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-popper": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"react-fast-compare": "^3.0.1",
|
||||||
|
"warning": "^4.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@popperjs/core": "^2.0.0",
|
||||||
|
"react": "^16.8.0 || ^17 || ^18",
|
||||||
|
"react-dom": "^16.8.0 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-ssr-prepass": {
|
"node_modules/react-ssr-prepass": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz",
|
||||||
|
|
@ -6183,6 +6208,14 @@
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/warning": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
@ -7650,6 +7683,11 @@
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@popperjs/core": {
|
||||||
|
"version": "2.11.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
|
||||||
|
"integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw=="
|
||||||
|
},
|
||||||
"@prisma/client": {
|
"@prisma/client": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.12.0.tgz",
|
||||||
|
|
@ -10181,6 +10219,15 @@
|
||||||
"react-fast-compare": "^3.0.1"
|
"react-fast-compare": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-popper": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
|
||||||
|
"requires": {
|
||||||
|
"react-fast-compare": "^3.0.1",
|
||||||
|
"warning": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-ssr-prepass": {
|
"react-ssr-prepass": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz",
|
||||||
|
|
@ -10707,6 +10754,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||||
},
|
},
|
||||||
|
"warning": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
"@aws-sdk/s3-request-presigner": "^3.310.0",
|
"@aws-sdk/s3-request-presigner": "^3.310.0",
|
||||||
"@headlessui/react": "^1.7.13",
|
"@headlessui/react": "^1.7.13",
|
||||||
"@next-auth/prisma-adapter": "^1.0.5",
|
"@next-auth/prisma-adapter": "^1.0.5",
|
||||||
|
"@popperjs/core": "^2.11.7",
|
||||||
"@prisma/client": "^4.11.0",
|
"@prisma/client": "^4.11.0",
|
||||||
"@tanstack/react-query": "^4.28.0",
|
"@tanstack/react-query": "^4.28.0",
|
||||||
"@trpc/client": "^10.18.0",
|
"@trpc/client": "^10.18.0",
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-player": "^2.12.0",
|
"react-player": "^2.12.0",
|
||||||
|
"react-popper": "^2.3.0",
|
||||||
"superjson": "1.12.2",
|
"superjson": "1.12.2",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
72
src/components/ExpireDateSelectMenu.tsx
Normal file
72
src/components/ExpireDateSelectMenu.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { Listbox, Transition } from "@headlessui/react";
|
||||||
|
import { Fragment, useState } from "react";
|
||||||
|
import { getTime } from "~/utils/getTime";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
shareExpiryAt: Date | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ExpireDateSelectMenu({ shareExpiryAt }: Props) {
|
||||||
|
const handleChange = (value) => {
|
||||||
|
console.log("selecting value", value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableExpireDates = [
|
||||||
|
"Never expire",
|
||||||
|
"In 1 hour",
|
||||||
|
"In 24 hours",
|
||||||
|
"In 7 days",
|
||||||
|
"In 30 days",
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Listbox value={shareExpiryAt} onChange={handleChange}>
|
||||||
|
<div>
|
||||||
|
<Listbox.Button className="h-6 rounded border border-solid border-[#d5d9df] bg-white px-[7px] font-medium">
|
||||||
|
<span className="block truncate">
|
||||||
|
{typeof shareExpiryAt === null
|
||||||
|
? getTime(shareExpiryAt)
|
||||||
|
: "Never expire"}
|
||||||
|
</span>
|
||||||
|
</Listbox.Button>
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
enter="transition ease-out duration-100"
|
||||||
|
enterFrom="transform opacity-0 scale-95"
|
||||||
|
enterTo="transform opacity-100 scale-100"
|
||||||
|
leave="transition ease-in duration-75"
|
||||||
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
|
leaveTo="transform opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Listbox.Options className="absolute z-10 mt-1 max-h-60 max-h-[300px] w-[220px] w-full overflow-auto rounded-md bg-white py-1 py-2 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||||
|
{availableExpireDates.map((person, personIdx) => (
|
||||||
|
<Listbox.Option
|
||||||
|
key={personIdx}
|
||||||
|
className={({ active }) =>
|
||||||
|
`relative mx-2 flex h-8 cursor-pointer select-none items-center rounded px-2 ${
|
||||||
|
active ? "bg-[#f3f4f6]" : "text-gray-900"
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
value={person}
|
||||||
|
>
|
||||||
|
{({ selected }) => (
|
||||||
|
<>
|
||||||
|
<span
|
||||||
|
className={`block truncate ${
|
||||||
|
selected ? "font-medium" : "font-normal"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{person}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Listbox.Option>
|
||||||
|
))}
|
||||||
|
</Listbox.Options>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</Listbox>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import { Dialog, Transition } from "@headlessui/react";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useState } from "react";
|
||||||
import { ModernSwitch } from "~/components/ModernSwitch";
|
import { ModernSwitch } from "~/components/ModernSwitch";
|
||||||
import { api, type RouterOutputs } from "~/utils/api";
|
import { api, type RouterOutputs } from "~/utils/api";
|
||||||
|
import ExpireDateSelectMenu from "~/components/ExpireDateSelectMenu";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
video: RouterOutputs["video"]["get"];
|
video: RouterOutputs["video"]["get"];
|
||||||
|
|
@ -97,7 +98,7 @@ export function ShareModal({ video }: Props) {
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded bg-white p-6 text-left align-middle text-[#292D34] shadow-xl transition-all">
|
<Dialog.Panel className="w-full max-w-md transform rounded bg-white p-6 text-left align-middle text-[#292D34] shadow-xl transition-all">
|
||||||
<div className="flex flex-col items-start">
|
<div className="flex flex-col items-start">
|
||||||
<span className="text-lg font-medium">
|
<span className="text-lg font-medium">
|
||||||
Share this recording
|
Share this recording
|
||||||
|
|
@ -127,9 +128,9 @@ export function ShareModal({ video }: Props) {
|
||||||
<div className="w-full border border-solid border-[#e9ebf0] bg-[#fafbfc] px-[15px] py-3 text-xs">
|
<div className="w-full border border-solid border-[#e9ebf0] bg-[#fafbfc] px-[15px] py-3 text-xs">
|
||||||
<div className="flex h-6 items-center justify-between">
|
<div className="flex h-6 items-center justify-between">
|
||||||
<span>Expire link</span>
|
<span>Expire link</span>
|
||||||
<button className="h-6 rounded border border-solid border-[#d5d9df] bg-white px-[7px] font-medium">
|
<ExpireDateSelectMenu
|
||||||
Never expire
|
shareExpiryAt={video.shareExpiryAt}
|
||||||
</button>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 flex h-6 items-center justify-between">
|
<div className="mt-3 flex h-6 items-center justify-between">
|
||||||
<span>Delete video after link expires</span>
|
<span>Delete video after link expires</span>
|
||||||
|
|
|
||||||
41
src/utils/use-popper.ts
Normal file
41
src/utils/use-popper.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { type RefCallback, useRef, useCallback, useMemo } from "react";
|
||||||
|
import { createPopper, type Options } from "@popperjs/core";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example implementation to use Popper: https://popper.js.org/
|
||||||
|
*/
|
||||||
|
export function usePopper(
|
||||||
|
options?: Partial<Options>
|
||||||
|
): [RefCallback<Element | null>, RefCallback<HTMLElement | null>] {
|
||||||
|
let reference = useRef<Element>(null);
|
||||||
|
let popper = useRef<HTMLElement>(null);
|
||||||
|
|
||||||
|
let cleanupCallback = useRef(() => {});
|
||||||
|
|
||||||
|
let instantiatePopper = useCallback(() => {
|
||||||
|
if (!reference.current) return;
|
||||||
|
if (!popper.current) return;
|
||||||
|
|
||||||
|
if (cleanupCallback.current) cleanupCallback.current();
|
||||||
|
|
||||||
|
cleanupCallback.current = createPopper(
|
||||||
|
reference.current,
|
||||||
|
popper.current,
|
||||||
|
options
|
||||||
|
).destroy;
|
||||||
|
}, [reference, popper, cleanupCallback, options]);
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => [
|
||||||
|
(referenceDomNode) => {
|
||||||
|
reference.current = referenceDomNode;
|
||||||
|
instantiatePopper();
|
||||||
|
},
|
||||||
|
(popperDomNode) => {
|
||||||
|
popper.current = popperDomNode;
|
||||||
|
instantiatePopper();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[reference, popper, instantiatePopper]
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue