ソースを参照

Add copy check

Owen Schwartz 8 ヶ月 前
コミット
dbb57171c7

+ 1 - 1
src/app/[orgId]/components/Header.tsx

@@ -93,7 +93,7 @@ export default function Header({ email, orgName, name }: HeaderProps) {
                             </DropdownMenuLabel>
                             </DropdownMenuLabel>
                             <DropdownMenuSeparator />
                             <DropdownMenuSeparator />
                             <DropdownMenuGroup>
                             <DropdownMenuGroup>
-                                <DropdownMenuItem>Profile</DropdownMenuItem>
+                                <Link href="/profile"><DropdownMenuItem>Profile</DropdownMenuItem></Link>
                                 <DropdownMenuItem>Log out</DropdownMenuItem>
                                 <DropdownMenuItem>Log out</DropdownMenuItem>
                             </DropdownMenuGroup>
                             </DropdownMenuGroup>
                         </DropdownMenuContent>
                         </DropdownMenuContent>

+ 50 - 73
src/app/[orgId]/sites/[siteId]/components/create-site.tsx

@@ -1,13 +1,13 @@
 "use client"
 "use client"
 
 
 import { zodResolver } from "@hookform/resolvers/zod"
 import { zodResolver } from "@hookform/resolvers/zod"
-import { CalendarIcon, CaretSortIcon, CheckIcon } from "@radix-ui/react-icons"
+import { CalendarIcon, CaretSortIcon, CheckIcon, ChevronDownIcon } from "@radix-ui/react-icons"
 import { useForm } from "react-hook-form"
 import { useForm } from "react-hook-form"
 import { z } from "zod"
 import { z } from "zod"
 
 
 import { cn } from "@/lib/utils"
 import { cn } from "@/lib/utils"
 import { toast } from "@/hooks/use-toast"
 import { toast } from "@/hooks/use-toast"
-import { Button } from "@/components/ui/button"
+import { Button, buttonVariants } from "@/components/ui/button"
 import {
 import {
     Command,
     Command,
     CommandEmpty,
     CommandEmpty,
@@ -37,6 +37,7 @@ import { api } from "@/api";
 import { AxiosResponse } from "axios"
 import { AxiosResponse } from "axios"
 import { useParams } from "next/navigation";
 import { useParams } from "next/navigation";
 import { useRouter } from "next/navigation";
 import { useRouter } from "next/navigation";
+import { Checkbox } from "@app/components/ui/checkbox"
 
 
 const method = [
 const method = [
     { label: "Wireguard", value: "wg" },
     { label: "Wireguard", value: "wg" },
@@ -62,9 +63,7 @@ const accountFormSchema = z.object({
         .max(30, {
         .max(30, {
             message: "Subdomain must not be longer than 30 characters.",
             message: "Subdomain must not be longer than 30 characters.",
         }),
         }),
-    method: z.string({
-        required_error: "Please select a method.",
-    }),
+    method: z.enum(["wg", "newt"]),
 });
 });
 
 
 type AccountFormValues = z.infer<typeof accountFormSchema>;
 type AccountFormValues = z.infer<typeof accountFormSchema>;
@@ -75,14 +74,18 @@ const defaultValues: Partial<AccountFormValues> = {
 };
 };
 
 
 export function CreateSiteForm() {
 export function CreateSiteForm() {
-    const [methodValue, setMethodValue] = useState("wg");
-    const [keypair, setKeypair] = useState<{ publicKey: string; privateKey: string } | null>(null);
-    const [isLoading, setIsLoading] = useState(true);
-
     const params = useParams();
     const params = useParams();
     const orgId = params.orgId;
     const orgId = params.orgId;
     const router = useRouter();
     const router = useRouter();
 
 
+    const [keypair, setKeypair] = useState<{ publicKey: string; privateKey: string } | null>(null);
+    const [isLoading, setIsLoading] = useState(true);
+    const [isChecked, setIsChecked] = useState(false);
+
+    const handleCheckboxChange = (checked: boolean) => {
+        setIsChecked(checked);
+    };
+
     const form = useForm<AccountFormValues>({
     const form = useForm<AccountFormValues>({
         resolver: zodResolver(accountFormSchema),
         resolver: zodResolver(accountFormSchema),
         defaultValues,
         defaultValues,
@@ -124,15 +127,15 @@ export function CreateSiteForm() {
 
 
     const wgConfig = keypair
     const wgConfig = keypair
         ? `[Interface]
         ? `[Interface]
-  Address = 10.0.0.2/24
-  ListenPort = 51820
-  PrivateKey = ${keypair.privateKey}
-  
-  [Peer]
-  PublicKey = ${keypair.publicKey}
-  AllowedIPs = 0.0.0.0/0, ::/0
-  Endpoint = myserver.dyndns.org:51820
-  PersistentKeepalive = 5`
+Address = 10.0.0.2/24
+ListenPort = 51820
+PrivateKey = ${keypair.privateKey}
+
+[Peer]
+PublicKey = ${keypair.publicKey}
+AllowedIPs = 0.0.0.0/0, ::/0
+Endpoint = myserver.dyndns.org:51820
+PersistentKeepalive = 5`
         : "";
         : "";
 
 
     const newtConfig = `curl -fsSL https://get.docker.com -o get-docker.sh
     const newtConfig = `curl -fsSL https://get.docker.com -o get-docker.sh
@@ -178,59 +181,23 @@ sh get-docker.sh`;
                         control={form.control}
                         control={form.control}
                         name="method"
                         name="method"
                         render={({ field }) => (
                         render={({ field }) => (
-                            <FormItem className="flex flex-col">
+                            <FormItem>
                                 <FormLabel>Method</FormLabel>
                                 <FormLabel>Method</FormLabel>
-                                <Popover>
-                                    <PopoverTrigger asChild>
-                                        <FormControl>
-                                            <Button
-                                                variant="outline"
-                                                role="combobox"
-                                                className={cn(
-                                                    "w-[200px] justify-between",
-                                                    !field.value && "text-muted-foreground"
-                                                )}
-                                            >
-                                                {field.value
-                                                    ? method.find(
-                                                        (method) => method.value === field.value
-                                                    )?.label
-                                                    : "Select method"}
-                                                <CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
-                                            </Button>
-                                        </FormControl>
-                                    </PopoverTrigger>
-                                    <PopoverContent className="w-[200px] p-0">
-                                        <Command>
-                                            <CommandInput placeholder="Search method..." />
-                                            <CommandList>
-                                                <CommandEmpty>No method found.</CommandEmpty>
-                                                <CommandGroup>
-                                                    {method.map((method) => (
-                                                        <CommandItem
-                                                            value={method.label}
-                                                            key={method.value}
-                                                            onSelect={() => {
-                                                                form.setValue("method", method.value);
-                                                                setMethodValue(method.value);
-                                                            }}
-                                                        >
-                                                            <CheckIcon
-                                                                className={cn(
-                                                                    "mr-2 h-4 w-4",
-                                                                    method.value === field.value
-                                                                        ? "opacity-100"
-                                                                        : "opacity-0"
-                                                                )}
-                                                            />
-                                                            {method.label}
-                                                        </CommandItem>
-                                                    ))}
-                                                </CommandGroup>
-                                            </CommandList>
-                                        </Command>
-                                    </PopoverContent>
-                                </Popover>
+                                <div className="relative w-max">
+                                    <FormControl>
+                                        <select
+                                            className={cn(
+                                                buttonVariants({ variant: "outline" }),
+                                                "w-[200px] appearance-none font-normal"
+                                            )}
+                                            {...field}
+                                        >
+                                            <option value="wg">WireGuard</option>
+                                            <option value="newt">Newt</option>
+                                        </select>
+                                    </FormControl>
+                                    <ChevronDownIcon className="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
+                                </div>
                                 <FormDescription>
                                 <FormDescription>
                                     This is how you will connect your site to Fossorial.
                                     This is how you will connect your site to Fossorial.
                                 </FormDescription>
                                 </FormDescription>
@@ -238,18 +205,28 @@ sh get-docker.sh`;
                             </FormItem>
                             </FormItem>
                         )}
                         )}
                     />
                     />
-                    {methodValue === "wg" && !isLoading ? (
+                    {form.watch("method") === "wg" && !isLoading ? (
                         <pre className="mt-2 w-full rounded-md bg-slate-950 p-4 overflow-x-auto">
                         <pre className="mt-2 w-full rounded-md bg-slate-950 p-4 overflow-x-auto">
                             <code className="text-white whitespace-pre-wrap">{wgConfig}</code>
                             <code className="text-white whitespace-pre-wrap">{wgConfig}</code>
                         </pre>
                         </pre>
-                    ) : methodValue === "wg" && isLoading ? (
+                    ) : form.watch("method") === "wg" && isLoading ? (
                         <p>Loading WireGuard configuration...</p>
                         <p>Loading WireGuard configuration...</p>
                     ) : (
                     ) : (
                         <pre className="mt-2 w-full rounded-md bg-slate-950 p-4 overflow-x-auto">
                         <pre className="mt-2 w-full rounded-md bg-slate-950 p-4 overflow-x-auto">
                             <code className="text-white whitespace-pre-wrap">{newtConfig}</code>
                             <code className="text-white whitespace-pre-wrap">{newtConfig}</code>
                         </pre>
                         </pre>
                     )}
                     )}
-                    <Button type="submit">Create Site</Button>
+                    <div className="flex items-center space-x-2">
+                        <Checkbox id="terms" checked={isChecked}
+                            onCheckedChange={handleCheckboxChange} />
+                        <label
+                            htmlFor="terms"
+                            className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+                        >
+                            I have copied the config
+                        </label>
+                    </div>
+                    <Button type="submit" disabled={!isChecked}>Create Site</Button>
                 </form>
                 </form>
             </Form>
             </Form>
         </>
         </>

+ 1 - 1
src/app/[orgId]/sites/[siteId]/layout.tsx

@@ -78,7 +78,7 @@ export default async function SettingsLayout({ children, params }: SettingsLayou
                 <div className="space-y-0.5">
                 <div className="space-y-0.5">
                     <h2 className="text-2xl font-bold tracking-tight">Settings</h2>
                     <h2 className="text-2xl font-bold tracking-tight">Settings</h2>
                     <p className="text-muted-foreground">
                     <p className="text-muted-foreground">
-                        { params.siteId == "create" ? "Create site..." : "Manage settings on site " + params.siteId }.
+                        { params.siteId == "create" ? "Create site..." : "Manage settings on " + site?.name || ""}.
                     </p>
                     </p>
                 </div>
                 </div>
                 <Separator className="my-6" />
                 <Separator className="my-6" />

+ 11 - 0
src/app/profile/layout.tsx

@@ -3,6 +3,7 @@ import Image from "next/image"
 
 
 import { Separator } from "@/components/ui/separator"
 import { Separator } from "@/components/ui/separator"
 import { SidebarNav } from "@/components/sidebar-nav"
 import { SidebarNav } from "@/components/sidebar-nav"
+import Header from "../[orgId]/components/Header"
 
 
 export const metadata: Metadata = {
 export const metadata: Metadata = {
   title: "Forms",
   title: "Forms",
@@ -39,6 +40,16 @@ interface SettingsLayoutProps {
 export default function SettingsLayout({ children }: SettingsLayoutProps) {
 export default function SettingsLayout({ children }: SettingsLayoutProps) {
   return (
   return (
     <>
     <>
+
+<div className="w-full bg-stone-200 border-b border-stone-300 mb-6 select-none sm:px-0 px-3">
+                <div className="container mx-auto flex flex-col content-between gap-4 pt-2">
+                    <Header
+                        email={"user.email"}
+                        orgName={"Profile"}
+                    />
+                </div>
+            </div>
+
       <div className="md:hidden">
       <div className="md:hidden">
         <Image
         <Image
           src="/configuration/forms-light.png"
           src="/configuration/forms-light.png"