make app usable without account, remove extra stuff
This commit is contained in:
@ -5,7 +5,7 @@ import { z } from "zod";
|
||||
import db from "~/utils/db.server";
|
||||
import logger from "~/utils/logger.server";
|
||||
import { validate } from "~/utils/validation.server";
|
||||
import { requireLoggedIn } from "~/utils/auth.server";
|
||||
import { getSession } from "~/utils/session.server";
|
||||
|
||||
const action: ActionFunction = async ({ request }) => {
|
||||
const formData = await request.clone().formData();
|
||||
@ -31,7 +31,6 @@ const action: ActionFunction = async ({ request }) => {
|
||||
export default action;
|
||||
|
||||
async function subscribe(request: Request) {
|
||||
const { organization } = await requireLoggedIn(request);
|
||||
const formData = await request.formData();
|
||||
const body = {
|
||||
subscription: JSON.parse(formData.get("subscription")?.toString() ?? "{}"),
|
||||
@ -42,17 +41,16 @@ async function subscribe(request: Request) {
|
||||
}
|
||||
|
||||
const { subscription } = validation.data;
|
||||
const membership = await db.membership.findFirst({
|
||||
where: { id: organization.membershipId },
|
||||
});
|
||||
if (!membership) {
|
||||
return notFound("Phone number not found");
|
||||
const session = await getSession(request);
|
||||
const twilio = session.get("twilio");
|
||||
if (!twilio) {
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
|
||||
try {
|
||||
await db.notificationSubscription.create({
|
||||
data: {
|
||||
membershipId: membership.id,
|
||||
twilioAccountSid: twilio.accountSid,
|
||||
endpoint: subscription.endpoint,
|
||||
expirationTime: subscription.expirationTime,
|
||||
keys_p256dh: subscription.keys.p256dh,
|
||||
|
@ -1,26 +0,0 @@
|
||||
import type { ButtonHTMLAttributes, FunctionComponent } from "react";
|
||||
import { useTransition } from "@remix-run/react";
|
||||
import clsx from "clsx";
|
||||
|
||||
type Props = ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const Button: FunctionComponent<Props> = ({ children, ...props }) => {
|
||||
const transition = useTransition();
|
||||
|
||||
return (
|
||||
<button
|
||||
className={clsx(
|
||||
"w-full flex justify-center py-2 px-4 border border-transparent text-base font-medium rounded-md text-white focus:outline-none focus:border-primary-700 focus:shadow-outline-primary transition duration-150 ease-in-out",
|
||||
{
|
||||
"bg-primary-400 cursor-not-allowed": transition.state === "submitting",
|
||||
"bg-primary-600 hover:bg-primary-700": transition.state !== "submitting",
|
||||
},
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Button;
|
@ -1,35 +0,0 @@
|
||||
import { useNavigate } from "@remix-run/react";
|
||||
import { IoSettings, IoAlertCircleOutline } from "react-icons/io5";
|
||||
|
||||
export default function InactiveSubscription() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="flex items-end justify-center min-h-full overflow-y-hidden pt-4 px-4 pb-4 text-center md:block md:p-0 z-10">
|
||||
<span className="hidden md:inline-block md:align-middle md:h-screen">​</span>
|
||||
<div className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all md:my-8 md:align-middle md:max-w-lg md:w-full md:p-6">
|
||||
<div className="text-center my-auto p-4">
|
||||
<IoAlertCircleOutline className="mx-auto h-12 w-12 text-gray-400" aria-hidden="true" />
|
||||
<h3 className="mt-2 text-sm font-medium text-gray-900">
|
||||
You don't have any active subscription
|
||||
</h3>
|
||||
<p className="mt-1 text-sm text-gray-500 max-w-sm mx-auto break-normal whitespace-normal">
|
||||
You need an active subscription to use this feature.
|
||||
<br />
|
||||
Head over to your settings to pick a plan.
|
||||
</p>
|
||||
<div className="mt-6">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-primary-500 focus:outline-none focus:ring-2 focus:ring-offset-2"
|
||||
onClick={() => navigate("/settings/billing")}
|
||||
>
|
||||
<IoSettings className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
|
||||
Choose a plan
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
import { Fragment } from "react";
|
||||
import { Listbox, Transition } from "@headlessui/react";
|
||||
import { HiCheck as CheckIcon, HiSelector as SelectorIcon } from "react-icons/hi";
|
||||
import clsx from "clsx";
|
||||
|
||||
type Option = { name: string; value: string };
|
||||
|
||||
type Props = {
|
||||
options: Option[];
|
||||
onChange: (selectedValue: Option) => void;
|
||||
value: Option;
|
||||
};
|
||||
|
||||
export default function Select({ options, onChange, value }: Props) {
|
||||
return (
|
||||
<Listbox value={value} onChange={onChange}>
|
||||
<div className="relative mt-1">
|
||||
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md cursor-default focus:outline-none focus-visible:ring-2 focus-visible:ring-opacity-75 focus-visible:ring-white focus-visible:ring-offset-orange-300 focus-visible:ring-offset-2 focus-visible:border-indigo-500 sm:text-sm">
|
||||
<span className="block truncate">{value.name}</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||
<SelectorIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="absolute w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{options.map((option, index) => (
|
||||
<Listbox.Option
|
||||
key={`option-${option}-${index}`}
|
||||
className={({ active }) =>
|
||||
clsx(
|
||||
"cursor-default select-none relative py-2 pl-10 pr-4",
|
||||
active ? "text-amber-900 bg-amber-100" : "text-gray-900",
|
||||
)
|
||||
}
|
||||
value={option}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={clsx("block truncate", selected ? "font-medium" : "font-normal")}
|
||||
>
|
||||
{option.name}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span
|
||||
className={clsx(
|
||||
"absolute inset-y-0 left-0 flex items-center pl-3",
|
||||
active ? "text-amber-600" : "text-amber-600",
|
||||
)}
|
||||
>
|
||||
<CheckIcon className="w-5 h-5" aria-hidden="true" />
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
.ring {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 3px solid rgba(0, 0, 0, 0.15);
|
||||
border-radius: 50%;
|
||||
border-top-color: currentColor;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import type { LinksFunction } from "@remix-run/node";
|
||||
|
||||
import styles from "./spinner.css";
|
||||
|
||||
export const links: LinksFunction = () => [
|
||||
{ rel: "stylesheet", href: styles },
|
||||
];
|
||||
|
||||
export default function Spinner() {
|
||||
return (
|
||||
<div className="h-full flex">
|
||||
<div className="ring m-auto text-primary-400" />
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user