Skip to content

Commit 4a852cb

Browse files
committed
Merge branch 'main' into layout-fixes
2 parents b840461 + d8bac45 commit 4a852cb

File tree

6 files changed

+149
-128
lines changed

6 files changed

+149
-128
lines changed

apps/desktop/src/routes/(window-chrome)/settings/general.tsx

Lines changed: 97 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
164164

165165
type SettingsGroup = {
166166
title: string;
167+
os?: "macos" | "windows" | "linux";
167168
titleStyling?: string;
168169
items: SettingItem[];
169170
};
@@ -190,6 +191,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
190191
},
191192
{
192193
title: "App",
194+
os: "macos",
193195
items: [
194196
{
195197
label: "Hide dock icon",
@@ -383,100 +385,106 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
383385

384386
<For each={settingsGroups}>
385387
{(group) => (
386-
<div>
387-
<h3
388-
class={cx(
389-
"mb-3 text-sm text-gray-12 w-fit",
390-
group.titleStyling,
391-
)}
392-
>
393-
{group.title}
394-
</h3>
395-
<div class="px-3 rounded-xl border divide-y divide-gray-3 border-gray-3 bg-gray-2">
396-
<For each={group.items}>
397-
{(item) => {
398-
// Check OS compatibility
399-
if (
400-
item.type === "toggle" &&
401-
item.os &&
402-
item.os !== ostype
403-
) {
404-
return null;
405-
}
406-
407-
if (item.type === "toggle") {
408-
return (
409-
<ToggleSetting
410-
pro={group.title === "Cap Pro"}
411-
label={item.label}
412-
description={item.description}
413-
value={item.value}
414-
onChange={item.onChange}
415-
/>
416-
);
417-
} else if (item.type === "select") {
388+
<Show when={group.os === ostype || !group.os}>
389+
<div>
390+
<h3
391+
class={cx(
392+
"mb-3 text-sm text-gray-12 w-fit",
393+
group.titleStyling,
394+
)}
395+
>
396+
{group.title}
397+
</h3>
398+
<div class="px-3 rounded-xl border divide-y divide-gray-3 border-gray-3 bg-gray-2">
399+
<For each={group.items}>
400+
{(item) => {
401+
// Check OS compatibility
418402
if (
419-
item.label === "Main window recording start behaviour"
420-
) {
421-
return renderRecordingSelect(
422-
item.label,
423-
item.description,
424-
() => item.value,
425-
item.onChange,
426-
[
427-
{ text: "Close", value: "close" },
428-
{ text: "Minimise", value: "minimise" },
429-
],
430-
);
431-
} else if (
432-
item.label === "Studio recording finish behaviour"
433-
) {
434-
return renderRecordingSelect(
435-
item.label,
436-
item.description,
437-
() => item.value,
438-
item.onChange,
439-
[
440-
{ text: "Open editor", value: "openEditor" },
441-
{ text: "Show in overlay", value: "showOverlay" },
442-
],
443-
);
444-
} else if (item.label === "Recording countdown") {
445-
return renderRecordingSelect(
446-
item.label,
447-
item.description,
448-
() => item.value,
449-
item.onChange,
450-
[
451-
{ text: "Off", value: 0 },
452-
{ text: "3 seconds", value: 3 },
453-
{ text: "5 seconds", value: 5 },
454-
{ text: "10 seconds", value: 10 },
455-
],
456-
);
457-
} else if (
458-
item.label === "After deleting recording behaviour"
403+
item.type === "toggle" &&
404+
item.os &&
405+
item.os !== ostype
459406
) {
460-
return renderRecordingSelect(
461-
item.label,
462-
item.description,
463-
() => item.value,
464-
item.onChange,
465-
[
466-
{ text: "Do Nothing", value: "doNothing" },
467-
{
468-
text: "Reopen Recording Window",
469-
value: "reopenRecordingWindow",
470-
},
471-
],
407+
return null;
408+
}
409+
410+
if (item.type === "toggle") {
411+
return (
412+
<ToggleSetting
413+
pro={group.title === "Cap Pro"}
414+
label={item.label}
415+
description={item.description}
416+
value={item.value}
417+
onChange={item.onChange}
418+
/>
472419
);
420+
} else if (item.type === "select") {
421+
if (
422+
item.label ===
423+
"Main window recording start behaviour"
424+
) {
425+
return renderRecordingSelect(
426+
item.label,
427+
item.description,
428+
() => item.value,
429+
item.onChange,
430+
[
431+
{ text: "Close", value: "close" },
432+
{ text: "Minimise", value: "minimise" },
433+
],
434+
);
435+
} else if (
436+
item.label === "Studio recording finish behaviour"
437+
) {
438+
return renderRecordingSelect(
439+
item.label,
440+
item.description,
441+
() => item.value,
442+
item.onChange,
443+
[
444+
{ text: "Open editor", value: "openEditor" },
445+
{
446+
text: "Show in overlay",
447+
value: "showOverlay",
448+
},
449+
],
450+
);
451+
} else if (item.label === "Recording countdown") {
452+
return renderRecordingSelect(
453+
item.label,
454+
item.description,
455+
() => item.value,
456+
item.onChange,
457+
[
458+
{ text: "Off", value: 0 },
459+
{ text: "3 seconds", value: 3 },
460+
{ text: "5 seconds", value: 5 },
461+
{ text: "10 seconds", value: 10 },
462+
],
463+
);
464+
} else if (
465+
item.label === "After deleting recording behaviour"
466+
) {
467+
return renderRecordingSelect(
468+
item.label,
469+
item.description,
470+
() => item.value,
471+
item.onChange,
472+
[
473+
{ text: "Do Nothing", value: "doNothing" },
474+
{
475+
text: "Reopen Recording Window",
476+
value: "reopenRecordingWindow",
477+
},
478+
],
479+
);
480+
}
473481
}
474-
}
475-
return null;
476-
}}
477-
</For>
482+
return null;
483+
}}
484+
</For>
485+
</div>
478486
</div>
479-
</div>
487+
</Show>
480488
)}
481489
</For>
482490

apps/web/app/(org)/dashboard/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default async function DashboardLayout({
2626
redirect("/login");
2727
}
2828

29-
if (!user.name || user.name.length <= 1) {
29+
if (!user.name || user.name.length === 0) {
3030
redirect("/onboarding");
3131
}
3232

apps/web/app/(org)/dashboard/settings/account/Settings.tsx

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,50 @@
22

33
import type { users } from "@cap/database/schema";
44
import { Button, Card, CardDescription, CardTitle, Input } from "@cap/ui";
5+
import { useMutation } from "@tanstack/react-query";
56
import { useRouter } from "next/navigation";
7+
import { useState } from "react";
68
import { toast } from "sonner";
79

810
export const Settings = ({
911
user,
1012
}: {
1113
user?: typeof users.$inferSelect | null;
1214
}) => {
13-
const firstName = user ? user?.name : "";
14-
const lastName = user ? user?.lastName : "";
15-
const email = user ? user?.email : "";
15+
const [firstName, setFirstName] = useState(user?.name || "");
16+
const [lastName, setLastName] = useState(user?.lastName || "");
1617
const router = useRouter();
1718

18-
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
19-
e.preventDefault();
20-
21-
const formData = new FormData(e.currentTarget);
22-
const firstName = formData.get("firstName") as string;
23-
const lastName = formData.get("lastName") as string;
24-
25-
try {
26-
const response = await fetch("/api/settings/user/name", {
19+
const { mutate: updateName, isPending: updateNamePending } = useMutation({
20+
mutationFn: async () => {
21+
const res = await fetch("/api/settings/user/name", {
2722
method: "POST",
28-
headers: {
29-
"Content-Type": "application/json",
30-
},
31-
body: JSON.stringify({ firstName, lastName }),
23+
headers: { "Content-Type": "application/json" },
24+
body: JSON.stringify({
25+
firstName: firstName.trim(),
26+
lastName: lastName.trim() ? lastName.trim() : null,
27+
}),
3228
});
33-
34-
if (response.ok) {
35-
toast.success("Name updated successfully");
36-
router.refresh();
37-
} else {
38-
toast.error("Failed to update name");
29+
if (!res.ok) {
30+
throw new Error("Failed to update name");
3931
}
40-
} catch (error) {
41-
console.error("Error updating name:", error);
42-
toast.error("An error occurred while updating name");
43-
}
44-
};
32+
},
33+
onSuccess: () => {
34+
toast.success("Name updated successfully");
35+
router.refresh();
36+
},
37+
onError: () => {
38+
toast.error("Failed to update name");
39+
},
40+
});
4541

4642
return (
47-
<form onSubmit={handleSubmit}>
43+
<form
44+
onSubmit={(e) => {
45+
e.preventDefault();
46+
updateName();
47+
}}
48+
>
4849
<div className="flex flex-col flex-wrap gap-6 w-full md:flex-row">
4950
<Card className="flex-1 space-y-1">
5051
<CardTitle>Your name</CardTitle>
@@ -57,6 +58,7 @@ export const Settings = ({
5758
<Input
5859
type="text"
5960
placeholder="First name"
61+
onChange={(e) => setFirstName(e.target.value)}
6062
defaultValue={firstName as string}
6163
id="firstName"
6264
name="firstName"
@@ -66,6 +68,7 @@ export const Settings = ({
6668
<Input
6769
type="text"
6870
placeholder="Last name"
71+
onChange={(e) => setLastName(e.target.value)}
6972
defaultValue={lastName as string}
7073
id="lastName"
7174
name="lastName"
@@ -82,15 +85,22 @@ export const Settings = ({
8285
</div>
8386
<Input
8487
type="email"
85-
value={email as string}
88+
value={user?.email as string}
8689
id="contactEmail"
8790
name="contactEmail"
8891
disabled
8992
/>
9093
</Card>
9194
</div>
92-
<Button className="mt-6" type="submit" size="sm" variant="dark">
93-
Save
95+
<Button
96+
disabled={!firstName || updateNamePending}
97+
className="mt-6"
98+
type="submit"
99+
size="sm"
100+
variant="dark"
101+
spinner={updateNamePending}
102+
>
103+
{updateNamePending ? "Saving..." : "Save"}
94104
</Button>
95105
</form>
96106
);

apps/web/app/(org)/onboarding/Onboarding.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,14 @@ export const Onboarding = () => {
7474
id="lastName"
7575
name="lastName"
7676
placeholder="Last name"
77-
required
7877
value={lastName}
7978
disabled={loading || isRedirecting}
8079
onChange={(e) => setLastName(e.target.value)}
8180
/>
8281
</div>
8382
</div>
8483
<Button
85-
disabled={!firstName || !lastName || loading || isRedirecting}
84+
disabled={!firstName || loading || isRedirecting}
8685
className="mx-auto mt-6 w-full"
8786
type="submit"
8887
spinner={loading || isRedirecting}

apps/web/app/api/desktop/[...route]/root.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ app.get("/plan", async (c) => {
9797

9898
let isSubscribed = userIsPro(user);
9999

100-
if (user.thirdPartyStripeSubscriptionId) {
101-
isSubscribed = true;
102-
}
103-
104100
if (!isSubscribed && !user.stripeSubscriptionId && user.stripeCustomerId) {
105101
try {
106102
const subscriptions = await stripe().subscriptions.list({

packages/utils/src/constants/plans.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,21 @@ export const getProPlanId = (billingCycle: "yearly" | "monthly") => {
2121
export const userIsPro = (
2222
user?: {
2323
stripeSubscriptionStatus?: string | null;
24+
thirdPartyStripeSubscriptionId?: string | null;
2425
} | null,
2526
) => {
2627
if (!buildEnv.NEXT_PUBLIC_IS_CAP) return true;
2728

2829
if (!user) return false;
2930

30-
const { stripeSubscriptionStatus } = user;
31+
const { stripeSubscriptionStatus, thirdPartyStripeSubscriptionId } = user;
32+
33+
// Check for third-party subscription first
34+
if (thirdPartyStripeSubscriptionId) {
35+
return true;
36+
}
37+
38+
// Then check regular subscription status
3139
return (
3240
stripeSubscriptionStatus === "active" ||
3341
stripeSubscriptionStatus === "trialing" ||

0 commit comments

Comments
 (0)