Skip to content

Commit b12e1fa

Browse files
committed
Merge branch 'main' into ai-integration
2 parents 59e67bd + b3e8ea5 commit b12e1fa

69 files changed

Lines changed: 4781 additions & 638 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

convex/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const schema = defineSchema({
3232
v.union(...validCapabilities.map((cap) => v.literal(cap)))
3333
),
3434
adsDisabled: v.optional(v.boolean()),
35+
interestedInHidingAds: v.optional(v.boolean()),
3536
}).searchIndex('search_email', {
3637
searchField: 'email',
3738
}),

convex/users.ts

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,19 @@ export const listUsers = query({
5151
page: v.optional(v.number()),
5252
}),
5353
emailFilter: v.optional(v.string()),
54+
nameFilter: v.optional(v.string()),
5455
capabilityFilter: v.optional(
55-
v.union(v.literal('admin'), v.literal('disableAds'), v.literal('builder'))
56+
v.array(
57+
v.union(
58+
v.literal('admin'),
59+
v.literal('disableAds'),
60+
v.literal('builder')
61+
)
62+
)
5663
),
64+
noCapabilitiesFilter: v.optional(v.boolean()),
5765
adsDisabledFilter: v.optional(v.boolean()),
66+
interestedInHidingAdsFilter: v.optional(v.boolean()),
5867
},
5968
handler: async (ctx, args) => {
6069
// Validate admin capability
@@ -80,17 +89,40 @@ export const listUsers = query({
8089
candidates.sort((a: any, b: any) => b._creationTime - a._creationTime)
8190

8291
const filtered = candidates.filter((user: any) => {
83-
if (args.capabilityFilter) {
92+
// Name filter (in-memory search on name and displayUsername)
93+
if (args.nameFilter && args.nameFilter.length > 0) {
94+
const name = (user.name || user.displayUsername || '').toLowerCase()
95+
const searchTerm = args.nameFilter.toLowerCase()
96+
if (!name.includes(searchTerm)) {
97+
return false
98+
}
99+
}
100+
101+
// No capabilities filter
102+
if (args.noCapabilitiesFilter === true) {
103+
if (!Array.isArray(user.capabilities) || user.capabilities.length > 0) {
104+
return false
105+
}
106+
}
107+
108+
if (args.capabilityFilter && args.capabilityFilter.length > 0) {
84109
if (
85110
!Array.isArray(user.capabilities) ||
86-
!user.capabilities.includes(args.capabilityFilter)
111+
!args.capabilityFilter.some((cap) => user.capabilities.includes(cap))
87112
) {
88113
return false
89114
}
90115
}
91116
if (typeof args.adsDisabledFilter === 'boolean') {
92117
if (Boolean(user.adsDisabled) !== args.adsDisabledFilter) return false
93118
}
119+
if (typeof args.interestedInHidingAdsFilter === 'boolean') {
120+
if (
121+
Boolean(user.interestedInHidingAds) !==
122+
args.interestedInHidingAdsFilter
123+
)
124+
return false
125+
}
94126
return true
95127
})
96128

@@ -171,3 +203,23 @@ export const adminSetAdsDisabled = mutation({
171203
return { success: true }
172204
},
173205
})
206+
207+
// Set interest in hiding ads (for opt-in waitlist)
208+
export const setInterestedInHidingAds = mutation({
209+
args: {
210+
interested: v.boolean(),
211+
},
212+
handler: async (ctx, args) => {
213+
const user = await getCurrentUserConvex(ctx)
214+
if (!user) {
215+
throw new Error('Not authenticated')
216+
}
217+
218+
// Update user's interestedInHidingAds flag
219+
await ctx.db.patch(user.userId as Id<'users'>, {
220+
interestedInHidingAds: args.interested,
221+
})
222+
223+
return { success: true }
224+
},
225+
})

media/brand.sketch

439 KB
Binary file not shown.

package.json

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,11 @@
6262
"downshift": "^9.0.9",
6363
"eslint-config-react-app": "^7.0.1",
6464
"gray-matter": "^4.0.3",
65+
"hast-util-is-element": "^3.0.0",
66+
"hast-util-to-string": "^3.0.1",
6567
"html-react-parser": "^5.1.10",
6668
"import-meta-resolve": "^4.0.0",
6769
"lru-cache": "^7.13.1",
68-
"marked": "^13.0.2",
69-
"marked-alert": "^2.0.1",
70-
"marked-gfm-heading-id": "^4.0.0",
7170
"mermaid": "^11.11.0",
7271
"qss": "^3.0.0",
7372
"react": "^19.2.0",
@@ -76,11 +75,22 @@
7675
"react-icons": "^5.3.0",
7776
"react-instantsearch": "7",
7877
"react-markdown": "^6.0.3",
78+
"rehype-autolink-headings": "^7.1.0",
79+
"rehype-callouts": "^2.1.2",
80+
"rehype-parse": "^9.0.1",
81+
"rehype-raw": "^7.0.0",
82+
"rehype-slug": "^6.0.0",
83+
"rehype-stringify": "^10.0.1",
84+
"remark-gfm": "^4.0.1",
85+
"remark-parse": "^11.0.0",
86+
"remark-rehype": "^11.1.2",
7987
"remix-utils": "^8.5.0",
8088
"remove-markdown": "^0.5.0",
8189
"shiki": "^1.4.0",
8290
"tailwind-merge": "^1.14.0",
8391
"tiny-invariant": "^1.3.3",
92+
"unified": "^11.0.5",
93+
"unist-util-visit": "^5.0.0",
8494
"vite-bundle-analyzer": "^1.2.1",
8595
"vite-tsconfig-paths": "^5.0.1",
8696
"zod": "^4.0.17",

0 commit comments

Comments
 (0)