@outseta/react 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outseta/react",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "React hooks and components for the Outseta API",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@tanstack/react-query": "^5.0.0",
22
- "@outseta/api-client": "0.2.5"
22
+ "@outseta/api-client": "0.3.0"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": "^18.0.0 || ^19.0.0"
@@ -0,0 +1,35 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ import { useOutseta } from "./OutsetaProvider.js";
3
+
4
+ export interface AuthCtaProps extends HTMLAttributes<HTMLDivElement> {
5
+ /** Message shown before the login/signup actions. */
6
+ message?: ReactNode;
7
+ /** Label for the signup button. */
8
+ signupLabel?: ReactNode;
9
+ /** Label for the login button. */
10
+ loginLabel?: ReactNode;
11
+ }
12
+
13
+ /**
14
+ * Generic login/signup call-to-action for gated content.
15
+ */
16
+ export function AuthCta({
17
+ message = "Sign up or log in to continue.",
18
+ signupLabel = "Sign up",
19
+ loginLabel = "Log in",
20
+ ...props
21
+ }: AuthCtaProps) {
22
+ const { openSignup, openLogin } = useOutseta();
23
+
24
+ return (
25
+ <div {...props}>
26
+ <p>{message}</p>
27
+ <button type="button" onClick={() => openSignup()}>
28
+ {signupLabel}
29
+ </button>{" "}
30
+ <button type="button" onClick={() => openLogin()}>
31
+ {loginLabel}
32
+ </button>
33
+ </div>
34
+ );
35
+ }
@@ -1,42 +1,56 @@
1
1
  import type { ReactNode } from "react";
2
2
  import { useOutseta } from "./OutsetaProvider.js";
3
+ import { AuthCta } from "./AuthCta.js";
4
+ import { UpgradeCta } from "./UpgradeCta.js";
3
5
 
4
6
  export interface ProtectedRouteProps {
5
- /** Plan UIDs that grant access to this route */
7
+ /** Plan UIDs that grant access to this route. */
6
8
  plans: string[];
7
- /** Content to render when access is granted */
9
+ /** Content to render when access is granted. */
8
10
  children: ReactNode;
9
- /** Rendered while checking auth status (defaults to null) */
11
+ /** Rendered while checking auth status. Defaults to null. */
10
12
  loading?: ReactNode;
11
- /** Rendered when user is logged in but lacks the right plan */
13
+ /** Rendered when user is logged in but lacks the right plan. */
12
14
  accessDenied?: ReactNode;
13
- /** Rendered when user is not logged in */
15
+ /** Rendered when user is not logged in. */
14
16
  unauthenticated?: ReactNode;
17
+ /** Message for the default unauthenticated CTA. */
18
+ unauthenticatedMessage?: ReactNode;
19
+ /** Message for the default upgrade/manage subscription CTA. */
20
+ accessDeniedMessage?: ReactNode;
15
21
  }
16
22
 
17
23
  /**
18
24
  * Protects content behind plan-based access control.
19
25
  *
20
- * Checks the current user's subscription plan UID against the
21
- * provided list of allowed plan UIDs.
26
+ * Checks the current user's subscription plan UID against the provided list of
27
+ * allowed plan UIDs. If access is denied, generic login/signup or upgrade CTAs
28
+ * are rendered by default and can be replaced with the `unauthenticated` and
29
+ * `accessDenied` props.
22
30
  */
23
31
  export function ProtectedRoute({
24
32
  plans,
25
33
  children,
26
34
  loading = null,
27
- accessDenied = null,
28
- unauthenticated = null,
35
+ accessDenied,
36
+ unauthenticated,
37
+ unauthenticatedMessage,
38
+ accessDeniedMessage,
29
39
  }: ProtectedRouteProps) {
30
40
  const { user, isLoading } = useOutseta();
31
41
 
32
42
  if (isLoading) return <>{loading}</>;
33
43
 
34
- if (!user) return <>{unauthenticated}</>;
44
+ if (!user) {
45
+ return <>{unauthenticated ?? <AuthCta message={unauthenticatedMessage} />}</>;
46
+ }
35
47
 
36
48
  const userPlanUid = user.Account?.CurrentSubscription?.Plan?.Uid;
37
49
  const hasAccess = userPlanUid ? plans.includes(userPlanUid) : false;
38
50
 
39
- if (!hasAccess) return <>{accessDenied}</>;
51
+ if (!hasAccess) {
52
+ return <>{accessDenied ?? <UpgradeCta message={accessDeniedMessage} />}</>;
53
+ }
40
54
 
41
55
  return <>{children}</>;
42
56
  }
@@ -0,0 +1,33 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ import { useOutseta } from "./OutsetaProvider.js";
3
+ import type { ProfileWidgetOptions } from "./types.js";
4
+
5
+ export interface UpgradeCtaProps extends HTMLAttributes<HTMLDivElement> {
6
+ /** Message shown before the upgrade/manage subscription action. */
7
+ message?: ReactNode;
8
+ /** Label for the profile/upgrade button. */
9
+ buttonLabel?: ReactNode;
10
+ /** Options passed to the Outseta profile widget. */
11
+ profileOptions?: ProfileWidgetOptions;
12
+ }
13
+
14
+ /**
15
+ * Generic upgrade/manage-subscription call-to-action for gated content.
16
+ */
17
+ export function UpgradeCta({
18
+ message = "Your current plan does not include access to this content.",
19
+ buttonLabel = "Manage subscription",
20
+ profileOptions = { tab: "planChange" },
21
+ ...props
22
+ }: UpgradeCtaProps) {
23
+ const { openProfile } = useOutseta();
24
+
25
+ return (
26
+ <div {...props}>
27
+ <p>{message}</p>
28
+ <button type="button" onClick={() => openProfile(profileOptions)}>
29
+ {buttonLabel}
30
+ </button>
31
+ </div>
32
+ );
33
+ }
@@ -12,6 +12,10 @@ export { ProfileEmbed } from "./ProfileEmbed.js";
12
12
  export type { ProfileEmbedProps } from "./ProfileEmbed.js";
13
13
  export { ProtectedRoute } from "./ProtectedRoute.js";
14
14
  export type { ProtectedRouteProps } from "./ProtectedRoute.js";
15
+ export { AuthCta } from "./AuthCta.js";
16
+ export type { AuthCtaProps } from "./AuthCta.js";
17
+ export { UpgradeCta } from "./UpgradeCta.js";
18
+ export type { UpgradeCtaProps } from "./UpgradeCta.js";
15
19
  export { PurchaseAddonButton } from "./PurchaseAddonButton.js";
16
20
  export type { PurchaseAddonButtonProps } from "./PurchaseAddonButton.js";
17
21
  export { LogoutButton } from "./LogoutButton.js";
package/src/index.ts CHANGED
@@ -4,5 +4,10 @@ export type { OutsetaCredentials } from "@outseta/api-client";
4
4
  // Outseta embed components and hooks
5
5
  export * from "./components/index.js";
6
6
 
7
- // Re-export generated React Query hooks once generated
8
- // export * from "./generated/index.js";
7
+ // Generated React Query hooks and schema types
8
+ export * from "./generated/activity/activity.js";
9
+ export * from "./generated/billing/billing.js";
10
+ export * from "./generated/crm/crm.js";
11
+ export * from "./generated/email/email.js";
12
+ export * from "./generated/support/support.js";
13
+ export * from "./generated/outsetaAPI.schemas.js";