Compare commits
1 Commits
fix/openap
...
fix/invite
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57eba407a2 |
@@ -5,10 +5,12 @@ const Toggle = ({
|
|||||||
isChecked,
|
isChecked,
|
||||||
onChange,
|
onChange,
|
||||||
label,
|
label,
|
||||||
|
disabled,
|
||||||
}: {
|
}: {
|
||||||
isChecked: boolean;
|
isChecked: boolean;
|
||||||
onChange: () => void;
|
onChange: () => void;
|
||||||
label: string;
|
label: string;
|
||||||
|
disabled?: boolean;
|
||||||
}) => (
|
}) => (
|
||||||
<div className="mr-4 flex items-center justify-end">
|
<div className="mr-4 flex items-center justify-end">
|
||||||
<span className="mr-2 text-xs text-light-900 dark:text-dark-900">
|
<span className="mr-2 text-xs text-light-900 dark:text-dark-900">
|
||||||
@@ -17,6 +19,7 @@ const Toggle = ({
|
|||||||
<Switch
|
<Switch
|
||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
disabled={disabled}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
"relative inline-flex h-4 w-6 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-light-800 transition-colors duration-200 ease-in-out focus:outline-none dark:bg-dark-800",
|
"relative inline-flex h-4 w-6 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-light-800 transition-colors duration-200 ease-in-out focus:outline-none dark:bg-dark-800",
|
||||||
isChecked && "bg-indigo-600 dark:bg-indigo-600",
|
isChecked && "bg-indigo-600 dark:bg-indigo-600",
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export function InviteMemberForm({
|
|||||||
const [isShareInviteLinkEnabled, setIsShareInviteLinkEnabled] =
|
const [isShareInviteLinkEnabled, setIsShareInviteLinkEnabled] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [inviteLink, setInviteLink] = useState<string>("");
|
const [inviteLink, setInviteLink] = useState<string>("");
|
||||||
const [isLoadingInviteLink, setIsLoadingInviteLink] = useState(false);
|
const [_isLoadingInviteLink, setIsLoadingInviteLink] = useState(false);
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const { closeModal } = useModal();
|
const { closeModal } = useModal();
|
||||||
const { workspace } = useWorkspace();
|
const { workspace } = useWorkspace();
|
||||||
@@ -68,7 +68,7 @@ export function InviteMemberForm({
|
|||||||
const refetchBoards = () => utils.board.all.refetch();
|
const refetchBoards = () => utils.board.all.refetch();
|
||||||
|
|
||||||
// Fetch active invite link on component mount
|
// Fetch active invite link on component mount
|
||||||
const { data: activeInviteLink, refetch: refetchInviteLink } =
|
const { data: activeInviteLink, refetch: _refetchInviteLink } =
|
||||||
api.member.getActiveInviteLink.useQuery(
|
api.member.getActiveInviteLink.useQuery(
|
||||||
{ workspacePublicId: workspace.publicId || "" },
|
{ workspacePublicId: workspace.publicId || "" },
|
||||||
{ enabled: !!workspace.publicId },
|
{ enabled: !!workspace.publicId },
|
||||||
@@ -78,7 +78,7 @@ export function InviteMemberForm({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeInviteLink) {
|
if (activeInviteLink) {
|
||||||
setIsShareInviteLinkEnabled(activeInviteLink.isActive);
|
setIsShareInviteLinkEnabled(activeInviteLink.isActive);
|
||||||
setInviteLink(activeInviteLink.inviteLink || "");
|
setInviteLink(activeInviteLink.inviteLink ?? "");
|
||||||
}
|
}
|
||||||
}, [activeInviteLink]);
|
}, [activeInviteLink]);
|
||||||
|
|
||||||
@@ -113,13 +113,23 @@ export function InviteMemberForm({
|
|||||||
setInviteLink(data.inviteLink);
|
setInviteLink(data.inviteLink);
|
||||||
setIsLoadingInviteLink(false);
|
setIsLoadingInviteLink(false);
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: (error) => {
|
||||||
setIsLoadingInviteLink(false);
|
setIsLoadingInviteLink(false);
|
||||||
showPopup({
|
setIsShareInviteLinkEnabled(false);
|
||||||
header: t`Error creating invite link`,
|
|
||||||
message: t`Please try again later.`,
|
if (error.data?.code === "FORBIDDEN") {
|
||||||
icon: "error",
|
showPopup({
|
||||||
});
|
header: t`Subscription Required`,
|
||||||
|
message: t`Invite links require a Team or Pro subscription. Please upgrade your workspace.`,
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showPopup({
|
||||||
|
header: t`Error creating invite link`,
|
||||||
|
message: t`Please try again later.`,
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -148,7 +158,7 @@ export function InviteMemberForm({
|
|||||||
let price = t`$10/month`;
|
let price = t`$10/month`;
|
||||||
let billingType = t`monthly billing`;
|
let billingType = t`monthly billing`;
|
||||||
|
|
||||||
if (teamSubscription?.periodStart && teamSubscription?.periodEnd) {
|
if (teamSubscription?.periodStart && teamSubscription.periodEnd) {
|
||||||
const periodStartDate = new Date(teamSubscription.periodStart);
|
const periodStartDate = new Date(teamSubscription.periodStart);
|
||||||
const periodEndDate = new Date(teamSubscription.periodEnd);
|
const periodEndDate = new Date(teamSubscription.periodEnd);
|
||||||
const diffInDays = Math.round(
|
const diffInDays = Math.round(
|
||||||
@@ -193,7 +203,7 @@ export function InviteMemberForm({
|
|||||||
message: t`Invite link copied to clipboard`,
|
message: t`Invite link copied to clipboard`,
|
||||||
icon: "success",
|
icon: "success",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch {
|
||||||
showPopup({
|
showPopup({
|
||||||
header: t`Error`,
|
header: t`Error`,
|
||||||
message: t`Failed to copy invite link`,
|
message: t`Failed to copy invite link`,
|
||||||
@@ -325,18 +335,20 @@ 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">
|
||||||
{(hasTeamSubscription || hasProSubscription) &&
|
<Toggle
|
||||||
env("NEXT_PUBLIC_KAN_ENV") === "cloud" && (
|
label={
|
||||||
<Toggle
|
isShareInviteLinkEnabled
|
||||||
label={
|
? t`Deactivate invite link`
|
||||||
isShareInviteLinkEnabled
|
: t`Create invite link`
|
||||||
? t`Deactivate invite link`
|
}
|
||||||
: t`Create invite link`
|
isChecked={isShareInviteLinkEnabled}
|
||||||
}
|
disabled={
|
||||||
isChecked={isShareInviteLinkEnabled}
|
env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
|
||||||
onChange={handleInviteLinkToggle}
|
!hasTeamSubscription &&
|
||||||
/>
|
!hasProSubscription
|
||||||
)}
|
}
|
||||||
|
onChange={handleInviteLinkToggle}
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
|
{env("NEXT_PUBLIC_KAN_ENV") === "cloud" &&
|
||||||
!hasTeamSubscription &&
|
!hasTeamSubscription &&
|
||||||
|
|||||||
@@ -362,6 +362,30 @@ export const memberRouter = createTRPCRouter({
|
|||||||
// Check if user is in workspace
|
// Check if user is in workspace
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
||||||
|
|
||||||
|
// Check subscription for cloud environment
|
||||||
|
if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") {
|
||||||
|
const subscriptions = await subscriptionRepo.getByReferenceId(
|
||||||
|
ctx.db,
|
||||||
|
workspace.publicId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const activeTeamSubscription = getSubscriptionByPlan(
|
||||||
|
subscriptions,
|
||||||
|
"team",
|
||||||
|
);
|
||||||
|
const activeProSubscription = getSubscriptionByPlan(
|
||||||
|
subscriptions,
|
||||||
|
"pro",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!activeTeamSubscription && !activeProSubscription) {
|
||||||
|
throw new TRPCError({
|
||||||
|
message: `Invite links require a Team or Pro subscription`,
|
||||||
|
code: "FORBIDDEN",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Deactivate any existing active invite links
|
// Deactivate any existing active invite links
|
||||||
await inviteLinkRepo.deactivateAllActiveForWorkspace(ctx.db, {
|
await inviteLinkRepo.deactivateAllActiveForWorkspace(ctx.db, {
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user