Skip to content

Commit 42f1a2d

Browse files
authored
Merge branch 'main' into chore/setup-router-eslint-plugin
2 parents e5b1795 + faf2ec5 commit 42f1a2d

30 files changed

Lines changed: 570 additions & 508 deletions

convex/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const schema = defineSchema({
3131
capabilities: v.array(
3232
v.union(...validCapabilities.map((cap) => v.literal(cap)))
3333
),
34+
adsDisabled: v.optional(v.boolean()),
3435
}),
3536
})
3637

convex/users.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { v } from 'convex/values'
22
import { mutation, query, QueryCtx } from './_generated/server'
33
import { Capability, CapabilitySchema } from './schema'
44
import { getCurrentUserConvex } from './auth'
5+
import { Id } from './_generated/dataModel'
56

67
export const updateUserCapabilities = mutation({
78
args: {
@@ -22,8 +23,6 @@ export const updateUserCapabilities = mutation({
2223

2324
let capabilities = args.capabilities
2425

25-
console.log('targetUser', targetUser)
26-
2726
// Ensure that tannerlinsley@gmail.com always has the admin capability
2827
// as a fail safe
2928
if (targetUser.email === 'tannerlinsley@gmail.com') {
@@ -32,8 +31,6 @@ export const updateUserCapabilities = mutation({
3231
]
3332
}
3433

35-
console.log(capabilities)
36-
3734
// Validate capabilities using schema helper
3835
const validatedCapabilities = CapabilitySchema.array().parse(capabilities)
3936

@@ -84,3 +81,21 @@ async function requireCapability(ctx: QueryCtx, capability: Capability) {
8481

8582
return { currentUser }
8683
}
84+
85+
// Toggle ad preference (only for users with disableAds capability)
86+
export const updateAdPreference = mutation({
87+
args: {
88+
adsDisabled: v.boolean(),
89+
},
90+
handler: async (ctx, args) => {
91+
// Validate admin capability
92+
const { currentUser } = await requireCapability(ctx, 'disableAds')
93+
94+
// Update target user's capabilities
95+
await ctx.db.patch(currentUser.userId as Id<'users'>, {
96+
adsDisabled: args.adsDisabled,
97+
})
98+
99+
return { success: true }
100+
},
101+
})

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
"@visx/hierarchy": "^2.10.0",
5252
"@visx/responsive": "^2.10.0",
5353
"@vitejs/plugin-react": "^4.3.3",
54-
"airtable": "^0.12.2",
5554
"algoliasearch": "^5.23.4",
5655
"axios": "^1.6.7",
5756
"better-auth": "^1.3.7",

pnpm-lock.yaml

Lines changed: 0 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Footer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Link } from '@tanstack/react-router'
22

33
const footerLinks = [
44
{ label: 'Blog', to: '/blog' },
5-
{ label: '@Tan_Stack Twitter', to: 'https://twitter.com/tan_stack' },
5+
{ label: '@Tan_Stack on X.com', to: 'https://x.com/tan_stack' },
66
{
7-
label: '@TannerLinsley Twitter',
7+
label: '@TannerLinsley on X.com',
88
to: 'https://twitter.com/tannerlinsley',
99
},
1010
{ label: 'GitHub', to: 'https://github.com/tanstack' },

src/components/OpenSourceStats.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,20 @@ const NpmDownloadCounter = ({
6161
return <StableCounter value={count} intervalMs={intervalMs} />
6262
}
6363

64+
export function ossStatsQuery({ library }: { library?: Library } = {}) {
65+
return convexQuery(api.stats.getStats, {
66+
library: library
67+
? {
68+
id: library.id,
69+
repo: library.repo,
70+
frameworks: library.frameworks,
71+
}
72+
: undefined,
73+
})
74+
}
75+
6476
export function _OssStats({ library }: { library?: Library }) {
65-
const { data: stats } = useSuspenseQuery(
66-
convexQuery(api.stats.getStats, {
67-
library: library
68-
? {
69-
id: library.id,
70-
repo: library.repo,
71-
frameworks: library.frameworks,
72-
}
73-
: undefined,
74-
})
75-
)
77+
const { data: stats } = useSuspenseQuery(ossStatsQuery({ library }))
7678

7779
return (
7880
<div>

src/components/SponsorPack.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,17 @@ import React from 'react'
22
import { Pack, hierarchy } from '@visx/hierarchy'
33
import { ParentSize } from '@visx/responsive'
44
import { twMerge } from 'tailwind-merge'
5+
import { getSponsorsForSponsorPack, Sponsor } from '~/server/sponsors'
56

6-
export default function SponsorPack({ sponsors }: { sponsors: any }) {
7+
type DisplaySponsor = Awaited<
8+
ReturnType<typeof getSponsorsForSponsorPack>
9+
>[number]
10+
11+
export default function SponsorPack({
12+
sponsors,
13+
}: {
14+
sponsors: DisplaySponsor[]
15+
}) {
716
const pack = React.useMemo(
817
() => ({
918
children: sponsors,
@@ -17,21 +26,11 @@ export default function SponsorPack({ sponsors }: { sponsors: any }) {
1726
const root = React.useMemo(
1827
() =>
1928
hierarchy(pack)
20-
.sum((d) => 1 + d?.tier?.monthlyPriceInDollars)
21-
.sort(
22-
(a, b) =>
23-
(b.data.tier?.monthlyPriceInDollars ?? 0) -
24-
(a.data.tier?.monthlyPriceInDollars ?? 0)
25-
),
29+
.sum((d) => 0.0007 + d.size)
30+
.sort((a, b) => (b.data.size ?? 0) - (a.data.size ?? 0)),
2631
[pack]
2732
)
2833

29-
// const [show, setShow] = React.useState(false)
30-
31-
// React.useEffect(() => {
32-
// setShow(true)
33-
// }, [])
34-
3534
return (
3635
<ParentSize>
3736
{({ width = 800 }) => {

src/hooks/useAdPreference.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useCurrentUserQuery } from './useCurrentUser'
2+
3+
// Legacy hook for backward compatibility - now uses current user query
4+
export function useAdsPreference() {
5+
const userQuery = useCurrentUserQuery()
6+
7+
if (userQuery.isLoading || !userQuery.data) {
8+
return { adsEnabled: true } // Default to showing ads while loading or not authenticated
9+
}
10+
11+
const user = userQuery.data
12+
const adsDisabled = user.adsDisabled ?? false
13+
const canDisableAds = user.capabilities.includes('disableAds')
14+
15+
// Ads are enabled if user can't disable them OR if they haven't disabled them
16+
const adsEnabled = !canDisableAds || !adsDisabled
17+
18+
return { adsEnabled }
19+
}

src/routes/_libraries/account.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,40 @@
1-
import { useUserSettingsStore } from '~/stores/userSettings'
21
import { FaSignOutAlt } from 'react-icons/fa'
3-
import { Authenticated, Unauthenticated } from 'convex/react'
2+
import { Authenticated, Unauthenticated, useMutation } from 'convex/react'
43
import { Link, redirect } from '@tanstack/react-router'
54
import { authClient } from '~/utils/auth.client'
65
import { useCurrentUserQuery } from '~/hooks/useCurrentUser'
6+
import { api } from 'convex/_generated/api'
77

88
export const Route = createFileRoute({
99
component: AccountPage,
1010
})
1111

1212
function UserSettings() {
1313
const userQuery = useCurrentUserQuery()
14-
const adsDisabled = useUserSettingsStore((s) => s.settings.adsDisabled)
15-
const toggleAds = useUserSettingsStore((s) => s.toggleAds)
14+
// Use current user query directly instead of separate ad preference query
15+
const updateAdPreferenceMutation = useMutation(
16+
api.users.updateAdPreference
17+
).withOptimisticUpdate((localStore, args) => {
18+
const { adsDisabled } = args
19+
const currentValue = localStore.getQuery(api.auth.getCurrentUser)
20+
if (currentValue !== undefined) {
21+
localStore.setQuery(api.auth.getCurrentUser, {}, {
22+
...currentValue,
23+
adsDisabled: adsDisabled,
24+
} as any)
25+
}
26+
})
1627

17-
const canDisableAds = userQuery.data?.capabilities.includes('disableAds')
28+
// Get values directly from the current user data
29+
const adsDisabled = userQuery.data?.adsDisabled ?? false
30+
const canDisableAds =
31+
userQuery.data?.capabilities.includes('disableAds') ?? false
32+
33+
const handleToggleAds = (e: React.ChangeEvent<HTMLInputElement>) => {
34+
updateAdPreferenceMutation({
35+
adsDisabled: e.target.checked,
36+
})
37+
}
1838

1939
const signOut = async () => {
2040
await authClient.signOut()
@@ -53,7 +73,7 @@ function UserSettings() {
5373
type="checkbox"
5474
className="h-4 w-4 accent-blue-600 my-1"
5575
checked={adsDisabled}
56-
onChange={toggleAds}
76+
onChange={handleToggleAds}
5777
disabled={userQuery.isLoading}
5878
aria-label="Disable Ads"
5979
/>

src/routes/_libraries/config.$version.index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ import { seo } from '~/utils/seo'
1111
import LandingPageGad from '~/components/LandingPageGad'
1212
import { PartnershipCallout } from '~/components/PartnershipCallout'
1313
import { PartnersSection } from '~/components/PartnersSection'
14-
import OpenSourceStats from '~/components/OpenSourceStats'
14+
import OpenSourceStats, { ossStatsQuery } from '~/components/OpenSourceStats'
15+
16+
const library = getLibrary('config')
1517

1618
export const Route = createFileRoute({
1719
component: FormVersionIndex,
20+
loader: async ({ context: { queryClient } }) => {
21+
await queryClient.ensureQueryData(ossStatsQuery({ library }))
22+
},
1823
head: () => ({
1924
meta: seo({
2025
title: configProject.name,
@@ -27,7 +32,6 @@ const librariesRouteApi = getRouteApi('/_libraries')
2732

2833
export default function FormVersionIndex() {
2934
const { sponsorsPromise } = librariesRouteApi.useLoaderData()
30-
const library = getLibrary('config')
3135

3236
return (
3337
<>

0 commit comments

Comments
 (0)