From cd4cbc800505b33a3369f323daa4289128c0d5ba Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Fri, 19 Dec 2025 23:03:16 +1100 Subject: [PATCH 1/2] Update React SDK --- packages/react-sdk/LICENSE | 7 +++ packages/react-sdk/README.md | 43 ++++++++++++++++--- .../src/components/ChangelogPost.tsx | 4 +- packages/react-sdk/src/hooks/index.ts | 6 ++- packages/react-sdk/src/hooks/usePosts.ts | 17 ++++++++ packages/react-sdk/src/index.ts | 6 ++- packages/react-sdk/src/types.ts | 1 + packages/react-sdk/src/utils.ts | 7 ++- 8 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 packages/react-sdk/LICENSE diff --git a/packages/react-sdk/LICENSE b/packages/react-sdk/LICENSE new file mode 100644 index 0000000..fb04d25 --- /dev/null +++ b/packages/react-sdk/LICENSE @@ -0,0 +1,7 @@ +Copyright 2025 Techulus + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/react-sdk/README.md b/packages/react-sdk/README.md index 4df7450..d8403e0 100644 --- a/packages/react-sdk/README.md +++ b/packages/react-sdk/README.md @@ -74,13 +74,46 @@ Render prop component exposing: ```tsx import { usePosts } from '@changespage/react'; -// Client-only (fetches on mount) -const { posts, hasMore, loading, loadMore } = usePosts({ client, limit: 10 }); +function ChangelogList() { + const { posts, hasMore, loading, error, loadMore, refetch } = usePosts({ + client, + limit: 10, + }); + + if (error) { + return ( +
+

Error: {error.message}

+ +
+ ); + } + + if (loading && posts.length === 0) { + return
Loading...
; + } -// With SSR initial data (skips initial fetch) -const { posts, hasMore, loading, loadMore } = usePosts({ + return ( +
+ {posts.map(post => ( +
{post.title}
+ ))} + {hasMore && ( + + )} +
+ ); +} +``` + +For SSR, pass initial data to skip the client-side fetch: + +```tsx +const { posts, hasMore, loading, error, loadMore, refetch } = usePosts({ client, - initialData: { posts: initialPosts, hasMore: initialHasMore }, + initialData: { posts: serverPosts, hasMore: serverHasMore }, limit: 10, }); ``` diff --git a/packages/react-sdk/src/components/ChangelogPost.tsx b/packages/react-sdk/src/components/ChangelogPost.tsx index 06c8765..a90e568 100644 --- a/packages/react-sdk/src/components/ChangelogPost.tsx +++ b/packages/react-sdk/src/components/ChangelogPost.tsx @@ -1,7 +1,7 @@ import type { ChangelogPostProps, ChangelogPostRenderProps } from "../types"; import { formatDate, parseDate } from "../utils"; -export function ChangelogPost({ post, children }: ChangelogPostProps) { +export function ChangelogPost({ post, locale, children }: ChangelogPostProps) { const renderProps: ChangelogPostRenderProps = { id: post.id, title: post.title, @@ -9,7 +9,7 @@ export function ChangelogPost({ post, children }: ChangelogPostProps) { plainText: post.plain_text_content, tags: post.tags, date: parseDate(post.publication_date), - formattedDate: formatDate(post.publication_date), + formattedDate: formatDate(post.publication_date, locale), url: post.url, }; diff --git a/packages/react-sdk/src/hooks/index.ts b/packages/react-sdk/src/hooks/index.ts index 35e8fb8..aea85e1 100644 --- a/packages/react-sdk/src/hooks/index.ts +++ b/packages/react-sdk/src/hooks/index.ts @@ -1,2 +1,6 @@ export { usePosts } from "./usePosts"; -export type { UsePostsOptions, UsePostsResult } from "./usePosts"; +export type { + UsePostsInitialData, + UsePostsOptions, + UsePostsResult, +} from "./usePosts"; diff --git a/packages/react-sdk/src/hooks/usePosts.ts b/packages/react-sdk/src/hooks/usePosts.ts index aa50f35..acc823f 100644 --- a/packages/react-sdk/src/hooks/usePosts.ts +++ b/packages/react-sdk/src/hooks/usePosts.ts @@ -20,6 +20,7 @@ export interface UsePostsResult { loading: boolean; error: Error | null; loadMore: () => Promise; + refetch: () => Promise; } export function usePosts({ @@ -84,11 +85,27 @@ export function usePosts({ } }, [client, posts.length, limit, loading, hasMore]); + const refetch = useCallback(async () => { + setLoading(true); + setError(null); + + try { + const result = await client.getPosts({ limit, offset: 0 }); + setPosts(result.posts); + setHasMore(result.hasMore); + } catch (e) { + setError(e instanceof Error ? e : new Error(String(e))); + } finally { + setLoading(false); + } + }, [client, limit]); + return { posts, hasMore, loading, error, loadMore, + refetch, }; } diff --git a/packages/react-sdk/src/index.ts b/packages/react-sdk/src/index.ts index 65e5e86..ef4aaeb 100644 --- a/packages/react-sdk/src/index.ts +++ b/packages/react-sdk/src/index.ts @@ -12,4 +12,8 @@ export type { Post, PostTag, } from "./types"; -export type { UsePostsOptions, UsePostsResult } from "./hooks"; +export type { + UsePostsInitialData, + UsePostsOptions, + UsePostsResult, +} from "./hooks"; diff --git a/packages/react-sdk/src/types.ts b/packages/react-sdk/src/types.ts index f582541..c5d8ee9 100644 --- a/packages/react-sdk/src/types.ts +++ b/packages/react-sdk/src/types.ts @@ -42,6 +42,7 @@ export interface ChangelogPostRenderProps { export interface ChangelogPostProps { post: Post; + locale?: string; children: (props: ChangelogPostRenderProps) => ReactNode; } diff --git a/packages/react-sdk/src/utils.ts b/packages/react-sdk/src/utils.ts index 0ff9ef8..14ddfba 100644 --- a/packages/react-sdk/src/utils.ts +++ b/packages/react-sdk/src/utils.ts @@ -12,11 +12,14 @@ export function getTagLabel(tag: PostTag): string { return tagLabels[tag] ?? tag; } -export function formatDate(dateString: string | null): string { +export function formatDate( + dateString: string | null, + locale: string = "en-US" +): string { if (!dateString) return ""; const date = new Date(dateString); - return date.toLocaleDateString("en-US", { + return date.toLocaleDateString(locale, { year: "numeric", month: "long", day: "numeric", From aac09fb7c0b44a2828dd273042187c16e9698e76 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Sat, 20 Dec 2025 00:37:16 +1100 Subject: [PATCH 2/2] Mention fair usage for storage and bandwidth --- apps/web/components/marketing/pricing-section.tsx | 10 +++++++++- apps/web/pages/pricing.tsx | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/web/components/marketing/pricing-section.tsx b/apps/web/components/marketing/pricing-section.tsx index 5dcc558..d08a3ea 100644 --- a/apps/web/components/marketing/pricing-section.tsx +++ b/apps/web/components/marketing/pricing-section.tsx @@ -55,7 +55,7 @@ export default function PricingSection({ unit_amount = 500, addons = [] }) {
    {features.map((feature) => (
  • @@ -67,6 +67,14 @@ export default function PricingSection({ unit_amount = 500, addons = [] }) {
  • ))}
+

+ + Fair usage applies to storage and bandwidth per page. + {" "} + We don't impose hard limits, but we may reach out if your + usage significantly exceeds typical patterns. We're here + to support growing teams, not restrict them. +

diff --git a/apps/web/pages/pricing.tsx b/apps/web/pages/pricing.tsx index 7d8a0fc..a6b3c47 100644 --- a/apps/web/pages/pricing.tsx +++ b/apps/web/pages/pricing.tsx @@ -12,6 +12,20 @@ export default function Pricing({ unit_amount, addons }) { +
+

+ Questions about pricing?{" "} + + Contact support + +

+
+