Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

Commit

Permalink
feat: add date picker for expiration
Browse files Browse the repository at this point in the history
  • Loading branch information
im-adithya committed Jul 4, 2024
1 parent 7ff26c0 commit 801cc06
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 33 deletions.
3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
Expand All @@ -41,12 +42,14 @@
"canvas-confetti": "^1.9.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"date-fns": "^3.6.0",
"dayjs": "^1.11.10",
"embla-carousel-react": "^8.0.2",
"gradient-avatar": "^1.0.2",
"lucide-react": "^0.363.0",
"posthog-js": "^1.116.6",
"react": "^18.2.0",
"react-day-picker": "^8.10.1",
"react-dom": "^18.2.0",
"react-lottie": "^1.2.4",
"react-qr-code": "^2.0.12",
Expand Down
106 changes: 80 additions & 26 deletions frontend/src/components/Permissions.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { PlusCircle, XIcon } from "lucide-react";
import { format } from "date-fns";
import { CalendarIcon, PlusCircle, XIcon } from "lucide-react";
import React, { useEffect, useState } from "react";
import Scopes from "src/components/Scopes";
import { Button } from "src/components/ui/button";
import { Calendar } from "src/components/ui/calendar";
import { Input } from "src/components/ui/input";
import { Label } from "src/components/ui/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "src/components/ui/popover";
import {
Select,
SelectContent,
Expand All @@ -23,6 +30,11 @@ import {
validBudgetRenewals,
} from "src/types";

const daysFromNow = (date?: Date) =>
date
? Math.ceil((new Date(date).getTime() - Date.now()) / (1000 * 60 * 60 * 24))
: 0;

interface PermissionsProps {
capabilities: WalletCapabilities;
initialPermissions: AppPermissions;
Expand All @@ -42,10 +54,13 @@ const Permissions: React.FC<PermissionsProps> = ({
const [permissions, setPermissions] = React.useState(initialPermissions);

// TODO: set expiry when set to non expiryType value like 24 days for example
const [expiryDays, setExpiryDays] = useState(0);
const [expiryDays, setExpiryDays] = useState(
daysFromNow(permissions.expiresAt)
);
const [budgetOption, setBudgetOption] = useState(!!permissions.maxAmount);
const [customBudget, setCustomBudget] = useState(!!permissions.maxAmount);
const [expireOption, setExpireOption] = useState(!!permissions.expiresAt);
const [customExpiry, setCustomExpiry] = useState(!!permissions.expiresAt);

useEffect(() => {
setPermissions(initialPermissions);
Expand Down Expand Up @@ -80,18 +95,20 @@ const Permissions: React.FC<PermissionsProps> = ({
return;
}
const currentDate = new Date();
const expiryDate = new Date(
Date.UTC(
currentDate.getUTCFullYear(),
currentDate.getUTCMonth(),
currentDate.getUTCDate() + expiryDays,
23,
59,
59,
0
)
);
handlePermissionsChange({ expiresAt: expiryDate });
// const expiryDate = new Date(
// Date.UTC(
// currentDate.getUTCFullYear(),
// currentDate.getUTCMonth(),
// currentDate.getUTCDate() + expiryDays,
// 23,
// 59,
// 59,
// 0
// )
// );
currentDate.setDate(currentDate.getDate() + expiryDays);
currentDate.setHours(23, 59, 59, 0);
handlePermissionsChange({ expiresAt: currentDate });
};

return (
Expand Down Expand Up @@ -148,7 +165,7 @@ const Permissions: React.FC<PermissionsProps> = ({
/>
</Select>
</div>
<div className="grid grid-cols-5 grid-rows-2 md:grid-rows-1 md:grid-cols-5 gap-2 text-xs mb-4">
<div className="grid grid-cols-2 md:grid-cols-5 gap-2 text-xs mb-4">
{Object.keys(budgetOptions).map((budget) => {
return (
// replace with something else and then remove dark prefixes
Expand All @@ -160,14 +177,15 @@ const Permissions: React.FC<PermissionsProps> = ({
budgetOptions[budget].toString()
);
}}
className={`col-span-2 md:col-span-1 cursor-pointer rounded text-nowrap border-2 ${
className={cn(
"cursor-pointer rounded text-nowrap border-2 text-center p-4 dark:text-white",
!customBudget &&
(permissions.maxAmount === ""
? 100000
: +permissions.maxAmount) == budgetOptions[budget]
(permissions.maxAmount === ""
? 100000
: +permissions.maxAmount) == budgetOptions[budget]
? "border-primary"
: "border-muted"
} text-center p-4 dark:text-white`}
)}
>
{`${budget} ${budgetOptions[budget] ? " sats" : ""}`}
</div>
Expand All @@ -178,9 +196,10 @@ const Permissions: React.FC<PermissionsProps> = ({
setCustomBudget(true);
handleBudgetMaxAmountChange("");
}}
className={`col-span-2 md:col-span-1 cursor-pointer rounded border-2 ${
className={cn(
"cursor-pointer rounded border-2 text-center p-4 dark:text-white",
customBudget ? "border-primary" : "border-muted"
} text-center p-4 dark:text-white`}
)}
>
Custom...
</div>
Expand Down Expand Up @@ -223,15 +242,18 @@ const Permissions: React.FC<PermissionsProps> = ({
{expireOption && (
<div className="mb-6">
<p className="font-medium text-sm mb-2">Connection expiration</p>
<div className="grid grid-cols-4 gap-2 text-xs">
<div className="grid grid-cols-2 md:grid-cols-6 gap-2 text-xs mb-4">
{Object.keys(expiryOptions).map((expiry) => {
return (
<div
key={expiry}
onClick={() => handleExpiryDaysChange(expiryOptions[expiry])}
onClick={() => {
setCustomExpiry(false);
handleExpiryDaysChange(expiryOptions[expiry]);
}}
className={cn(
"cursor-pointer rounded border-2 text-center p-4",
expiryDays == expiryOptions[expiry]
"cursor-pointer rounded text-nowrap border-2 text-center p-4 dark:text-white",
!customExpiry && expiryDays == expiryOptions[expiry]
? "border-primary"
: "border-muted"
)}
Expand All @@ -240,6 +262,38 @@ const Permissions: React.FC<PermissionsProps> = ({
</div>
);
})}
<Popover>
<PopoverTrigger asChild>
<div
onClick={() => {}}
className={cn(
"flex items-center justify-center md:col-span-2 cursor-pointer rounded text-nowrap border-2 text-center px-3 py-4 dark:text-white",
customExpiry ? "border-primary" : "border-muted"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
<span className="truncate">
{customExpiry && permissions.expiresAt
? format(permissions.expiresAt, "PPP")
: "Custom..."}
</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={permissions.expiresAt}
onSelect={(date?: Date) => {
if (daysFromNow(date) == 0) {
return;
}
setCustomExpiry(true);
handleExpiryDaysChange(daysFromNow(date));
}}
initialFocus
/>
</PopoverContent>
</Popover>
</div>
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Scopes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const Scopes: React.FC<ScopesProps> = ({
{scopeGroups.length > 1 && (
<div className="flex flex-col w-full mb-6">
<p className="font-medium text-sm mb-2">Choose wallet permissions</p>
<div className="flex gap-4">
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{(scopeGroups as ScopeGroupType[]).map((sg, index) => {
if (
scopeGroup == SCOPE_GROUP_SEND_RECEIVE &&
Expand Down
64 changes: 64 additions & 0 deletions frontend/src/components/ui/calendar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ChevronLeft, ChevronRight } from "lucide-react";
import * as React from "react";
import { DayPicker } from "react-day-picker";

import { buttonVariants } from "src/components/ui/button";
import { cn } from "src/lib/utils";

export type CalendarProps = React.ComponentProps<typeof DayPicker>;

function Calendar({
className,
classNames,
showOutsideDays = true,
...props
}: CalendarProps) {
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y-4",
caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-y-1",
head_row: "flex",
head_cell:
"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
day: cn(
buttonVariants({ variant: "ghost" }),
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
),
day_range_end: "day-range-end",
day_selected:
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside:
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle:
"aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible",
...classNames,
}}
components={{
IconLeft: () => <ChevronLeft className="h-4 w-4" />,
IconRight: () => <ChevronRight className="h-4 w-4" />,
}}
{...props}
/>
);
}
Calendar.displayName = "Calendar";

export { Calendar };
29 changes: 29 additions & 0 deletions frontend/src/components/ui/popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as PopoverPrimitive from "@radix-ui/react-popover";
import * as React from "react";

import { cn } from "src/lib/utils";

const Popover = PopoverPrimitive.Root;

const PopoverTrigger = PopoverPrimitive.Trigger;

const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;

export { Popover, PopoverContent, PopoverTrigger };
5 changes: 0 additions & 5 deletions frontend/src/screens/apps/NewApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,6 @@ const NewAppInternal = ({ capabilities }: NewAppInternalProps) => {
);
}

// TODO: CHECK DARK MODE
// TODO: Remove me!
console.log(permissions);
console.log(capabilities);

return (
<>
<AppHeader
Expand Down
Loading

0 comments on commit 801cc06

Please sign in to comment.