odd-box 0.1.7-preview

dead simple reverse proxy server
import SettingsItem from "../settings/settings-item";
import SettingsSection from "../settings/settings-section";
import Input from "../../components/input/input";
import "./style.css";
import Button from "../../components/button/button";
import useSiteMutations from "../../hooks/use-site-mutations";
import toast from "react-hot-toast";
import { useEffect, useState } from "react";
import { useRouter } from "@tanstack/react-router";
import { Backend, RemoteSiteConfig } from "../../generated-api";
import OddModal from "../../components/modal/modal";
import Plus2 from "../../components/icons/plus2";
import BackendModal from "../../components/backend_modal/backend_modal";
import SettingDescriptions from "@/lib/setting_descriptions";

type BackendModalState = {
  show: boolean;
  backend: Backend | undefined;
  listIndex: number;
};

const RemoteSiteSettings = ({ site }: { site: RemoteSiteConfig }) => {
  const { deleteSite, updateRemoteSite } = useSiteMutations();
  const [newName, setNewName] = useState(site?.host_name);

  const [showConfirmDeleteModal, setShowConfirmDeleteModal] = useState(false);
  const [backendModalState, setBackendModalState] = useState<BackendModalState>(
    {
      backend: undefined,
      show: false,
      listIndex: -1,
    }
  );

  useEffect(() => {
    setBackendModalState((old) => ({
      ...old,
      backends: site.backends,
    }));
  }, [site]);
  const router = useRouter();

  const updateSetting = (key: string, value: any) => {
    let val =
      Array.isArray(value) || isNaN(value) === false ? value : `${value}`;

    toast.promise(
      updateRemoteSite.mutateAsync({
        hostname: site.host_name,
        siteSettings: {
          ...site,
          [key]: val,
        },
      }),
      {
        loading: `Updating settings.. [${site.host_name}]`,
        success: `Settings updated! [${site.host_name}]`,
        error: (e) => `${e}`,
      }
    );
  };

  return (
    <div
      key={site.host_name}
      style={{ paddingBottom: "50px", maxWidth: "750px" }}
      onSubmit={(e) => {
        e.preventDefault();
      }}
    >
      <SettingsSection noTopSeparator>
        <SettingsItem
          title="Hostname"
          subTitle={SettingDescriptions["hostname_frontend"]}
        >
          <Input
            originalValue={site.host_name}
            onSave={(newValue) => {
              updateSetting("host_name", newValue);
            }}
            withSaveButton
            value={newName}
            onChange={(e) => setNewName(e.target.value)}
          />
        </SettingsItem>
      </SettingsSection>

      <SettingsSection noTopSeparator>
        <SettingsItem
          labelFor="capture_subdomains"
          rowOnly
          title="Capture sub-domains"
          subTitle={SettingDescriptions["capture_subdomains"]}
        >
          <Input
            onChange={() => {
              updateSetting("capture_subdomains", !site.capture_subdomains);
            }}
            checked={Boolean(site.capture_subdomains)}
            type="checkbox"
            name="capture_subdomains"
            id="capture_subdomains"
            style={{ width: "20px", height: "20px" }}
          />
        </SettingsItem>

        <SettingsItem
          rowOnly
          labelFor="disable_tcp_tunnel"
          title="Disable TCP tunnel mode"
          subTitle={SettingDescriptions["disable_tcp_tunnel"]}
        >
          <Input
            type="checkbox"
            checked={Boolean(site.disable_tcp_tunnel_mode)}
            onChange={() => {
              updateSetting(
                "disable_tcp_tunnel_mode",
                !site.disable_tcp_tunnel_mode
              );
            }}
            id="disable_tcp_tunnel"
            name="disable_tcp_tunnel"
            style={{ width: "20px", height: "20px" }}
          />
        </SettingsItem>

        <SettingsItem
          rowOnly
          labelFor="forward_subdomains"
          title="Forward sub-domains"
          subTitle={SettingDescriptions["forward_subdomains"]}
        >
          <Input
            type="checkbox"
            checked={Boolean(site.forward_subdomains)}
            onChange={() => {
              updateSetting("forward_subdomains", !site.forward_subdomains);
            }}
            id="forward_subdomains"
            name="forward_subdomains"
            style={{ width: "20px", height: "20px" }}
          />
        </SettingsItem>
      </SettingsSection>
      <SettingsSection noTopSeparator>
        <SettingsItem title="Backends" subTitle={SettingDescriptions["backends"]} />
        <div
          style={{
            background: "var(--color3)",
            color: "black",
            marginTop: "10px",
            borderRadius: "5px",
            overflow: "hidden",
          }}
        >
          {site.backends?.map((key, listIndex) => (
            <div
              key={JSON.stringify({ backend: key, index: listIndex })}
              onClick={() => {
                setBackendModalState({
                  backend: key,
                  show: true,
                  listIndex,
                });
              }}
              className="env-var-item"
              style={{
                display: "flex",
                justifyContent: "space-between",
                alignItems: "center",
                padding: "5px",
              }}
            >
              <p style={{ zIndex: 1, fontSize: ".8rem" }}>{key.address}</p>
            </div>
          ))}
          <div
            onClick={() => {
              updateRemoteSite.mutateAsync({
                hostname: site.host_name,
                siteSettings: {
                  ...site,
                  backends: [
                    ...site.backends,
                    {
                      address: "NEW_BACKEND",
                      port: 8080,
                      hints: [],
                      https: false,
                    },
                  ],
                },
              });
            }}
            className="env-var-item"
            style={{
              display: "flex",
              justifyContent: "space-between",
              alignItems: "center",
              padding: "5px",
            }}
          >
            <div
              style={{
                zIndex: 1,
                fontSize: ".8rem",
                display: "flex",
                alignItems: "center",
                gap: "5px",
              }}
            >
              <Plus2 />
              New backend
            </div>
          </div>
        </div>
      </SettingsSection>

      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "end",
          marginTop: "20px",
        }}
      >
        <Button
          onClick={() => {
            setShowConfirmDeleteModal(true);
          }}
          style={{ width: "max-content" }}
          dangerButton
        >
          Delete site
        </Button>
      </div>
      <OddModal
        key={JSON.stringify(backendModalState?.backend)}
        show={showConfirmDeleteModal}
        onClose={() => setShowConfirmDeleteModal(false)}
        title="Delete"
        subtitle={`Are you sure you want to delete the site '${site.host_name}'?`}
      >
        <div style={{ display: "flex", gap: "20px", marginTop: "10px" }}>
          <Button secondary onClick={() => setShowConfirmDeleteModal(false)}>
            Cancel
          </Button>
          <Button
            onClick={() => {
              deleteSite.mutateAsync(
                { hostname: site.host_name },
                {
                  onSuccess: () => {
                    setShowConfirmDeleteModal(false);
                    router.navigate({ to: "/" });
                  },
                }
              );
            }}
            dangerButton
          >
            Yes, delete
          </Button>
        </div>
      </OddModal>
      <BackendModal
        listIndex={backendModalState.listIndex}
        key={JSON.stringify(backendModalState.backend)}
        site={site}
        show={backendModalState.show}
        onClose={() =>
          setBackendModalState((old) => ({
            ...old,
            show: false,
          }))
        }
      />
    </div>
  );
};

export default RemoteSiteSettings;