Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: revamp permissions component #14

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,6 @@ func (api *api) parseExpiresAt(expiresAtString string) (*time.Time, error) {
logger.Logger.WithField("expiresAt", expiresAtString).Error("Invalid expiresAt")
return nil, fmt.Errorf("invalid expiresAt: %v", err)
}
expiresAtValue = time.Date(expiresAtValue.Year(), expiresAtValue.Month(), expiresAtValue.Day(), 23, 59, 59, 0, expiresAtValue.Location())
expiresAt = &expiresAtValue
}
return expiresAt, nil
Expand Down
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
81 changes: 62 additions & 19 deletions frontend/src/components/BudgetAmountSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,74 @@
import React from "react";
import { Input } from "src/components/ui/input";
import { Label } from "src/components/ui/label";
import { cn } from "src/lib/utils";
import { budgetOptions } from "src/types";

function BudgetAmountSelect({
value,
onChange,
}: {
value?: number;
value: number;
onChange: (value: number) => void;
}) {
const [customBudget, setCustomBudget] = React.useState(
value ? !Object.values(budgetOptions).includes(value) : false
);
return (
<div className="grid grid-cols-6 grid-rows-2 md:grid-rows-1 md:grid-cols-6 gap-2 text-xs">
{Object.keys(budgetOptions).map((budget) => {
const amount = budgetOptions[budget];
return (
<div
key={budget}
onClick={() => onChange(amount)}
className={`col-span-2 md:col-span-1 cursor-pointer rounded border-2 ${
value === amount ? "border-primary" : "border-muted"
} text-center py-4`}
>
{budget}
<br />
{amount ? "sats" : "#reckless"}
</div>
);
})}
</div>
<>
<div className="grid grid-cols-2 md:grid-cols-5 gap-2 text-xs mb-4">
{Object.keys(budgetOptions).map((budget) => {
return (
<div
key={budget}
onClick={() => {
setCustomBudget(false);
onChange(budgetOptions[budget]);
}}
className={cn(
"cursor-pointer rounded text-nowrap border-2 text-center p-4",
!customBudget && value == budgetOptions[budget]
? "border-primary"
: "border-muted"
)}
>
{`${budget} ${budgetOptions[budget] ? " sats" : ""}`}
</div>
);
})}
<div
onClick={() => {
setCustomBudget(true);
onChange(0);
}}
className={cn(
"cursor-pointer rounded border-2 text-center p-4 dark:text-white",
customBudget ? "border-primary" : "border-muted"
)}
>
Custom...
</div>
</div>
{customBudget && (
<div className="w-full mb-6">
<Label htmlFor="budget" className="block mb-2">
Custom budget amount (sats)
</Label>
<Input
id="budget"
name="budget"
type="number"
required
autoFocus
min={1}
value={value || ""}
onChange={(e) => {
onChange(parseInt(e.target.value));
}}
/>
</div>
)}
</>
);
}

Expand Down
39 changes: 25 additions & 14 deletions frontend/src/components/BudgetRenewalSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { XIcon } from "lucide-react";
import React from "react";
import { Label } from "src/components/ui/label";
import {
Select,
SelectContent,
Expand All @@ -11,27 +13,36 @@ import { BudgetRenewalType, validBudgetRenewals } from "src/types";
interface BudgetRenewalProps {
value: BudgetRenewalType;
onChange: (value: BudgetRenewalType) => void;
disabled?: boolean;
}

const BudgetRenewalSelect: React.FC<BudgetRenewalProps> = ({
value,
onChange,
disabled,
}) => {
return (
<Select value={value} onValueChange={onChange} disabled={disabled}>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder={"placeholder"} />
</SelectTrigger>
<SelectContent>
{validBudgetRenewals.map((renewalOption) => (
<SelectItem key={renewalOption} value={renewalOption}>
{renewalOption.charAt(0).toUpperCase() + renewalOption.slice(1)}
</SelectItem>
))}
</SelectContent>
</Select>
<>
<Label htmlFor="budget-renewal" className="block mb-2">
Budget Renewal
</Label>
<div className="flex gap-2 items-center text-muted-foreground mb-4 text-sm">
<Select value={value} onValueChange={onChange}>
<SelectTrigger id="budget-renewal" className="w-[150px] capitalize">
<SelectValue placeholder={value} />
</SelectTrigger>
<SelectContent className="capitalize">
{validBudgetRenewals.map((renewalOption) => (
<SelectItem key={renewalOption} value={renewalOption}>
{renewalOption}
</SelectItem>
))}
</SelectContent>
<XIcon
className="cursor-pointer w-4 text-muted-foreground"
onClick={() => onChange("never")}
/>
</Select>
</div>
</>
);
};

Expand Down
106 changes: 106 additions & 0 deletions frontend/src/components/ExpirySelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import dayjs from "dayjs";
import { CalendarIcon } from "lucide-react";
import React from "react";
import { Calendar } from "src/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "src/components/ui/popover";
import { cn } from "src/lib/utils";
import { expiryOptions } from "src/types";

const daysFromNow = (date?: Date) => {
if (!date) {
return 0;
}
const now = dayjs();
const targetDate = dayjs(date);
return targetDate.diff(now, "day");
};

interface ExpiryProps {
value?: Date | undefined;
onChange: (expiryDate?: Date) => void;
}

const ExpirySelect: React.FC<ExpiryProps> = ({ value, onChange }) => {
const [expiryDays, setExpiryDays] = React.useState(daysFromNow(value));
const [customExpiry, setCustomExpiry] = React.useState(
daysFromNow(value)
? !Object.values(expiryOptions).includes(daysFromNow(value))
: false
);
return (
<>
<p className="font-medium text-sm mb-2">Connection expiration</p>
<div className="grid grid-cols-2 md:grid-cols-6 gap-2 text-xs">
{Object.keys(expiryOptions).map((expiry) => {
return (
<div
key={expiry}
onClick={() => {
setCustomExpiry(false);
let date;
if (expiryOptions[expiry]) {
date = new Date();
date.setDate(date.getUTCDate() + expiryOptions[expiry]);
date.setHours(23, 59, 59);
}
onChange(date);
setExpiryDays(expiryOptions[expiry]);
}}
className={cn(
"cursor-pointer rounded text-nowrap border-2 text-center p-4",
!customExpiry && expiryDays == expiryOptions[expiry]
? "border-primary"
: "border-muted"
)}
>
{expiry}
</div>
);
})}
<Popover>
<PopoverTrigger asChild>
<div
onClick={() => {}}
className={cn(
"flex items-center justify-center md:col-span-2 cursor-pointer rounded text-nowrap border-2 p-4",
customExpiry ? "border-primary" : "border-muted"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
<span className="truncate">
{customExpiry && value
? dayjs(value).format("DD MMMM YYYY")
: "Custom..."}
</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
disabled={{
before: new Date(),
}}
selected={value}
onSelect={(date?: Date) => {
if (!date) {
return;
}
date.setHours(23, 59, 59);
setCustomExpiry(true);
onChange(date);
setExpiryDays(daysFromNow(date));
}}
initialFocus
/>
</PopoverContent>
</Popover>
</div>
</>
);
};

export default ExpirySelect;
Loading
Loading