feat: rework upgrade

This commit is contained in:
Henry
2025-09-02 22:19:42 +01:00
parent bc98fc848f
commit a596b1c40b
2 changed files with 71 additions and 43 deletions

View File

@@ -18,18 +18,22 @@ import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
export function InviteMemberForm({ export function InviteMemberForm({
numberOfMembers,
activeTeamSubscription, activeTeamSubscription,
userId,
}: { }: {
numberOfMembers: number;
activeTeamSubscription: activeTeamSubscription:
| { | {
id: string; id: number | null;
plan: string; plan: string;
status: string; status: string;
seats: number; seats: number | null;
periodStart: Date; periodStart: Date | null;
periodEnd: Date; periodEnd: Date | null;
} }
| undefined; | undefined;
userId: string | undefined;
}) { }) {
const utils = api.useUtils(); const utils = api.useUtils();
const [isCreateAnotherEnabled, setIsCreateAnotherEnabled] = useState(false); const [isCreateAnotherEnabled, setIsCreateAnotherEnabled] = useState(false);
@@ -103,32 +107,32 @@ export function InviteMemberForm({
billingType = isYearly ? t`billed annually` : t`billed monthly`; billingType = isYearly ? t`billed annually` : t`billed monthly`;
} }
const onSubmit = async (member: InviteMemberInput) => { const onSubmit = (member: InviteMemberInput) => {
if (env("NEXT_PUBLIC_KAN_ENV") === "cloud" && !activeTeamSubscription?.id) { inviteMember.mutate(member);
const { data, error } = await authClient.subscription.upgrade({ };
plan: "team",
referenceId: workspace.publicId, const handleUpgrade = async () => {
metadata: { userId: "123" }, // @todo: add the user id const { data, error } = await authClient.subscription.upgrade({
seats: 1, plan: "team",
successUrl: "/members", referenceId: workspace.publicId,
cancelUrl: "/members", metadata: { userId },
returnUrl: "/members", seats: numberOfMembers,
disableRedirect: true, successUrl: "/members",
cancelUrl: "/members",
returnUrl: "/members",
disableRedirect: true,
});
if (data?.url) {
window.location.href = data.url;
}
if (error) {
showPopup({
header: t`Error upgrading subscription`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
}); });
if (data?.url) {
window.location.href = data.url;
}
if (error) {
showPopup({
header: t`Error upgrading subscription`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
});
}
} else {
inviteMember.mutate(member);
} }
}; };
@@ -157,6 +161,10 @@ export function InviteMemberForm({
<Input <Input
id="email" id="email"
placeholder={t`Email`} placeholder={t`Email`}
disabled={
env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
!activeTeamSubscription?.id
}
{...register("email", { required: true })} {...register("email", { required: true })}
onKeyDown={async (e) => { onKeyDown={async (e) => {
if (e.key === "Enter") { if (e.key === "Enter") {
@@ -193,19 +201,36 @@ export function InviteMemberForm({
</div> </div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600"> <div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
<Toggle {activeTeamSubscription?.id &&
label={t`Invite another`} env("NEXT_PUBLIC_KAN_ENV") === "cloud" && (
isChecked={isCreateAnotherEnabled} <Toggle
onChange={() => setIsCreateAnotherEnabled(!isCreateAnotherEnabled)} label={t`Invite another`}
/> isChecked={isCreateAnotherEnabled}
onChange={() =>
setIsCreateAnotherEnabled(!isCreateAnotherEnabled)
}
/>
)}
<div> <div>
<Button {env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
type="submit" !activeTeamSubscription?.id ? (
isLoading={inviteMember.isPending} <Button
className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50" type="button"
> onClick={handleUpgrade}
{t`Invite member`} className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
</Button> >
{t`Upgrade to Team Plan`}
</Button>
) : (
<Button
type="submit"
disabled={inviteMember.isPending}
isLoading={inviteMember.isPending}
className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
>
{t`Invite member`}
</Button>
)}
</div> </div>
</div> </div>
</form> </form>

View File

@@ -28,6 +28,8 @@ export default function MembersPage() {
// { enabled: workspace?.publicId ? true : false }, // { enabled: workspace?.publicId ? true : false },
); );
const { data: session } = authClient.useSession();
const subscription = data?.subscriptions; const subscription = data?.subscriptions;
const activeTeamSubscription = subscription?.find( const activeTeamSubscription = subscription?.find(
@@ -57,7 +59,6 @@ export default function MembersPage() {
isLastRow?: boolean; isLastRow?: boolean;
showSkeleton?: boolean; showSkeleton?: boolean;
}) => { }) => {
const { data: session } = authClient.useSession();
return ( return (
<tr className="rounded-b-lg"> <tr className="rounded-b-lg">
<td <td
@@ -265,7 +266,9 @@ export default function MembersPage() {
isVisible={isOpen && modalContentType === "INVITE_MEMBER"} isVisible={isOpen && modalContentType === "INVITE_MEMBER"}
> >
<InviteMemberForm <InviteMemberForm
activeTeamSubscription={activeTeamSubscription as any} userId={session?.user.id}
numberOfMembers={data?.members.length ?? 1}
activeTeamSubscription={activeTeamSubscription}
/> />
</Modal> </Modal>