Skip to content

Instantly share code, notes, and snippets.

@RichardSPrins
Created September 15, 2022 18:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RichardSPrins/1e608f3906b0f5946f4994a9d3fbbe1f to your computer and use it in GitHub Desktop.
Save RichardSPrins/1e608f3906b0f5946f4994a9d3fbbe1f to your computer and use it in GitHub Desktop.
import * as React from "react";
import { GetServerSidePropsContext } from "next";
import { unstable_getServerSession } from "next-auth";
import AppLayout from "../../layouts/AppLayout";
import { trpc } from "../../utils/trpc";
import { authOptions } from "../api/auth/[...nextauth]";
import {
Button,
CopyButton,
Tooltip,
ActionIcon,
Input,
Popover,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { HiOutlineClipboardCopy, HiCheck } from "react-icons/hi";
import { IoMdHelpCircleOutline } from "react-icons/io";
import useQueryParams from "../../hooks/useQueryParams";
import { ParsedUrlQuery } from "querystring";
export default function AppSettingsPage() {
const queryParams = useQueryParams();
const [stripedata, setStripeData] = React.useState(null);
const [opened, { close, open }] = useDisclosure(false);
// const { data: config, status } = trpc.useQuery(["auth.getAuthUserConfig"]);
// const { data: currentUser, status: userStatus } = trpc.useQuery([
// "auth.getAuthUser",
// ]);
const {
data: stripeConnect,
error: stripeConnectError,
isLoading: stripeConnectLoading,
mutate: mutateStripeConnect,
} = trpc.useMutation(["stripe.connectStripe"]);
const [newDonationLink, setNewDonationLink] = React.useState<string | null>(
null
);
const [loadingNewLink, setLoadingNewLink] = React.useState<boolean>(false);
const handleGenerateNewLink = () => {
setLoadingNewLink(true);
setTimeout(() => {
setLoadingNewLink(false);
setNewDonationLink(
`${window.location.origin}/${Math.floor(
Math.random() * 99999999999
)}/donate`
);
}, 2000);
};
// React.useEffect(() => {
// if (!queryParams) {
// return;
// }
// if (
// Object.keys(queryParams).includes("scope") &&
// Object.keys(queryParams).includes("code")
// ) {
// handleStripeConnect(queryParams);
// console.log({ queryParams });
// }
// }, [queryParams]);
// const handleStripeConnect = async (queryParams: ParsedUrlQuery) => {
// const { scope, code } = queryParams;
// await mutateStripeConnect({
// scope: scope as string,
// code: code as string,
// });
// // setStripeData(result)
// console.log({ stripeConnect });
// };
return (
<AppLayout>
<p className="text-4xl font-bold">Account Settings</p>
<div className="max-w-4xl mx-auto mt-12 flex flex-col">
<div className="flex justify-end">
<Button color="green">Save Changes</Button>
</div>
<div className="mb-4 w-full">
<label
className="block text-gray-700 text-sm font-bold mb-1"
htmlFor="displayName"
>
Display Name
</label>
<Input placeholder="Your email" sx={{ maxWidth: "350px" }} />
<p className="text-xs text-slate-500 mt-2">
* This is necessary if you want to use a personalized name for your
donation link
</p>
</div>
<div className="mb-4 w-full">
<p className="block text-gray-700 text-sm font-bold mb-1">
Donation Link
</p>
{!newDonationLink && (
<p className="text-xs text-slate-500 my-3">
You do not have a donation link yet. Create one to start earning!
</p>
)}
{newDonationLink && (
<div className="flex gap-2 items-center my-2">
<span className="text-sm text-gray-700 bg-gray-100 px-2 rounded-sm">
{newDonationLink}
</span>
<CopyButton value={newDonationLink}>
{({ copied, copy }) => (
<Tooltip
label={copied ? "Copied" : "Copy"}
withArrow
position="top"
>
<ActionIcon color={copied ? "teal" : "gray"} onClick={copy}>
{copied ? <HiCheck /> : <HiOutlineClipboardCopy />}
</ActionIcon>
</Tooltip>
)}
</CopyButton>
</div>
)}
<Button
color="dark"
loading={loadingNewLink}
onClick={handleGenerateNewLink}
>
Generate New Link
</Button>
</div>
<div className="mb-4 w-full">
<div className="flex gap-1 items-center mb-1">
<p className="block text-gray-700 text-sm font-bold">
Stripe Account
</p>
</div>
<p className="text-xs text-slate-500 my-2">
* This is necessary to collect donation payments. Please connect a
Stripe account to use our services.
</p>
<Button
color={"blue"}
onClick={() => {
if (window) {
const url = `https://dashboard.stripe.com/oauth/authorize?response_type=code&client_id=${process.env.NEXT_PUBLIC_STRIPE_OAUTH_CLIENT_ID}&scope=read_write&redirect_uri=${process.env.NEXT_PUBLIC_BASE_URL}/app/account`;
window.document.location.href = url;
}
}}
>
Connect Stripe
</Button>
</div>
{/* <pre>{stripeData && JSON.stringify(stripeData, null, 2)}</pre> */}
</div>
</AppLayout>
);
}
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
);
if (!session) {
return {
redirect: { destination: "/sign-in" },
};
}
return {
props: {},
};
}
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { createProtectedRouter } from "./context";
export const stripeRouter = createProtectedRouter()
.middleware(async ({ ctx, next }) => {
// Any queries or mutations after this middleware will
// raise an error unless there is a current session
if (!ctx.session) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next();
})
.query("getBalance", {
resolve({ ctx }) {
// TODO: replace with Stripe Connected Account balance query result
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
// const balance = await stripe.balance.retrieve({
// stripeAccount: '{{CONNECTED_STRIPE_ACCOUNT_ID}}'
// });
return 100;
},
})
.mutation("connectStripe", {
input: z.object({ scope: z.string(), code: z.string() }),
async resolve({ ctx, input }) {
try {
const { scope, code } = input;
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
const result = await stripe.oauth
.token({
grant_type: "authorization_code",
code: code,
})
.catch((err: any) => {
throw new Error("Stripe oauth fail", err.message);
});
const account = await stripe.accounts
?.retrieve(result?.stripe_user_id)
?.catch((err: any) => {
throw new Error("Error fetching stripe account", err.message);
});
// Here we get the important details of the account.
const accountAnalysis = {
hasConnectedAccount: !!account?.id, // Check if account ID received is actually connected or exists.
accountId: account?.id,
hasCompletedProcess: account?.details_submitted,
isValid: account?.charges_enabled && account?.payouts_enabled,
displayName:
account?.settings?.dashboard?.display_name ||
account?.display_name ||
null,
country: account?.country,
currency: account?.default_currency,
};
// boolean - Once the account is connected, should we let it unlink?
const shouldAllowUnlink =
accountAnalysis?.hasConnectedAccount &&
(!accountAnalysis?.isValid ||
!accountAnalysis?.hasCompletedProcess ||
!accountAnalysis?.displayName);
return { oauth: result, account, accountAnalysis, shouldAllowUnlink };
} catch (error) {
console.log(error);
}
},
})
.mutation("handlePayout", {
input: z.object({}),
async resolve({ ctx, input }) {
try {
} catch (error) {}
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment