Skip to content

Commit 8fc4c03

Browse files
committed
ad disabler
1 parent f63b0f0 commit 8fc4c03

File tree

3 files changed

+78
-19
lines changed

3 files changed

+78
-19
lines changed

convex/users.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,28 @@ export const updateAdPreference = mutation({
9999
return { success: true }
100100
},
101101
})
102+
103+
// Admin override to set a user's adsDisabled flag
104+
export const adminSetAdsDisabled = mutation({
105+
args: {
106+
userId: v.id('users'),
107+
adsDisabled: v.boolean(),
108+
},
109+
handler: async (ctx, args) => {
110+
// Validate admin capability
111+
await requireCapability(ctx, 'admin')
112+
113+
// Validate that target user exists
114+
const targetUser = await ctx.db.get(args.userId)
115+
if (!targetUser) {
116+
throw new Error('Target user not found')
117+
}
118+
119+
// Update target user's adsDisabled flag
120+
await ctx.db.patch(args.userId, {
121+
adsDisabled: args.adsDisabled,
122+
})
123+
124+
return { success: true }
125+
},
126+
})

src/routes/__root.tsx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -220,35 +220,35 @@ function HtmlWrapper({ children }: { children: React.ReactNode }) {
220220
<GamScripts />
221221
</head>
222222
<body>
223-
<BackgroundGradient />
224223
<ToastProvider>
224+
<BackgroundGradient />
225225
<React.Suspense fallback={null}>{children}</React.Suspense>
226-
</ToastProvider>
227-
{showDevtools ? (
228-
<TanStackRouterDevtoolsInProd position="bottom-right" />
229-
) : null}
230-
{canShowLoading ? (
231-
<div
232-
className={`fixed top-0 left-0 h-[300px] w-full
226+
{showDevtools ? (
227+
<TanStackRouterDevtoolsInProd position="bottom-right" />
228+
) : null}
229+
{canShowLoading ? (
230+
<div
231+
className={`fixed top-0 left-0 h-[300px] w-full
233232
transition-all duration-300 pointer-events-none
234233
z-30 dark:h-[200px] dark:bg-white/10! dark:rounded-[100%] ${
235234
isLoading
236235
? 'delay-500 opacity-1 -translate-y-1/2'
237236
: 'delay-0 opacity-0 -translate-y-full'
238237
}`}
239-
style={{
240-
background: `radial-gradient(closest-side, rgba(0,10,40,0.2) 0%, rgba(0,0,0,0) 100%)`,
241-
}}
242-
>
243-
<div
244-
className={`absolute top-1/2 left-1/2 -translate-x-1/2 translate-y-[30px] p-2 bg-white/80 dark:bg-gray-800
245-
rounded-lg shadow-lg`}
238+
style={{
239+
background: `radial-gradient(closest-side, rgba(0,10,40,0.2) 0%, rgba(0,0,0,0) 100%)`,
240+
}}
246241
>
247-
<CgSpinner className="text-3xl animate-spin" />
242+
<div
243+
className={`absolute top-1/2 left-1/2 -translate-x-1/2 translate-y-[30px] p-2 bg-white/80 dark:bg-gray-800
244+
rounded-lg shadow-lg`}
245+
>
246+
<CgSpinner className="text-3xl animate-spin" />
247+
</div>
248248
</div>
249-
</div>
250-
) : null}
251-
<SearchModal />
249+
) : null}
250+
<SearchModal />
251+
</ToastProvider>
252252
<noscript>
253253
<iframe
254254
src="https://www.googletagmanager.com/ns.html?id=GTM-5N57KQT4"

src/routes/admin/users.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type User = {
3131
email: string
3232
image?: string
3333
capabilities?: string[]
34+
adsDisabled?: boolean
3435
}
3536

3637
export const Route = createFileRoute({
@@ -42,6 +43,9 @@ function UsersPage() {
4243
const [editingCapabilities, setEditingCapabilities] = useState<string[]>([])
4344
const [cursors, setCursors] = useState<string[]>(['']) // Track cursor history for navigation
4445
const [currentPageIndex, setCurrentPageIndex] = useState(0)
46+
const [updatingAdsUserId, setUpdatingAdsUserId] = useState<string | null>(
47+
null
48+
)
4549

4650
const user = useConvexQuery(api.auth.getCurrentUser)
4751
const usersQuery = useQuery({
@@ -57,6 +61,7 @@ function UsersPage() {
5761
const updateUserCapabilities = useConvexMutation(
5862
api.users.updateUserCapabilities
5963
)
64+
const adminSetAdsDisabled = useConvexMutation(api.users.adminSetAdsDisabled)
6065

6166
const availableCapabilities = useMemo(
6267
() => ['admin', 'disableAds', 'builder'],
@@ -104,6 +109,16 @@ function UsersPage() {
104109
[editingCapabilities]
105110
)
106111

112+
const handleToggleAdsDisabled = useCallback(
113+
async (userId: string, nextValue: boolean) => {
114+
adminSetAdsDisabled({
115+
userId: userId as Id<'users'>,
116+
adsDisabled: nextValue,
117+
})
118+
},
119+
[adminSetAdsDisabled]
120+
)
121+
107122
// Define columns using the column helper
108123
const columns = useMemo<ColumnDef<User, any>[]>(
109124
() => [
@@ -177,6 +192,25 @@ function UsersPage() {
177192
)
178193
},
179194
},
195+
{
196+
id: 'adsDisabled',
197+
header: 'Ads Disabled',
198+
cell: ({ row }) => {
199+
const user = row.original
200+
const checked = Boolean(user.adsDisabled)
201+
return (
202+
<input
203+
type="checkbox"
204+
checked={checked}
205+
onChange={(e) =>
206+
handleToggleAdsDisabled(user._id, e.target.checked)
207+
}
208+
disabled={updatingAdsUserId === user._id}
209+
className="h-4 w-4 accent-blue-600"
210+
/>
211+
)
212+
},
213+
},
180214
{
181215
id: 'actions',
182216
header: 'Actions',

0 commit comments

Comments
 (0)