Skip to content

Commit c7f9fec

Browse files
prazgaitisclaude
andcommitted
Rename challenge kind to special, matching forum rules terminology
The forum rules use three tiers: core (streak + category leaderboard), special (streak-eligible workouts, no category leaderboard), and bonus (not streak-eligible). Rename challenge → special to match. Four kinds: core, special, bonus, penalty. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4199149 commit c7f9fec

5 files changed

Lines changed: 20 additions & 20 deletions

File tree

apps/web/components/admin/admin-activity-types-table.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export function AdminActivityTypesTable({
159159
isNegative: createNegative,
160160
availableInFinalDays: createAvailableInFinalDays || undefined,
161161
categoryId: createCategoryId ? (createCategoryId as Id<"categories">) : undefined,
162-
kind: (createKind || undefined) as "core" | "challenge" | "bonus" | "penalty" | undefined,
162+
kind: (createKind || undefined) as "core" | "special" | "bonus" | "penalty" | undefined,
163163
displayOrder: Number.isFinite(parsedDisplayOrder) && createDisplayOrder !== "" ? parsedDisplayOrder : undefined,
164164
});
165165
setCreateName("");
@@ -256,7 +256,7 @@ export function AdminActivityTypesTable({
256256
availableInFinalDays: editAvailableInFinalDays || undefined,
257257
bonusThresholds: editThresholds,
258258
categoryId: editCategoryId ? (editCategoryId as Id<"categories">) : undefined,
259-
kind: (editKind || undefined) as "core" | "challenge" | "bonus" | "penalty" | undefined,
259+
kind: (editKind || undefined) as "core" | "special" | "bonus" | "penalty" | undefined,
260260
displayOrder: Number.isFinite(parsedDisplayOrder) && editDisplayOrder !== "" ? parsedDisplayOrder : undefined,
261261
});
262262
setEditingId(null);
@@ -422,7 +422,7 @@ export function AdminActivityTypesTable({
422422
>
423423
<option value=""></option>
424424
<option value="core">Core</option>
425-
<option value="challenge">Challenge</option>
425+
<option value="special">Special</option>
426426
<option value="bonus">Bonus</option>
427427
<option value="penalty">Penalty</option>
428428
</select>
@@ -654,7 +654,7 @@ export function AdminActivityTypesTable({
654654
>
655655
<option value=""></option>
656656
<option value="core">Core</option>
657-
<option value="challenge">Challenge</option>
657+
<option value="special">Special</option>
658658
<option value="bonus">Bonus</option>
659659
<option value="penalty">Penalty</option>
660660
</select>

apps/web/tests/api/activity-type-kind.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe("Activity type kind field", () => {
6464
it("updateActivityType updates kind", async () => {
6565
const id = await createTestActivityType(t, challengeId, {
6666
name: "Bonus",
67-
kind: "challenge",
67+
kind: "special",
6868
});
6969

7070
await tWithAuth.mutation(api.mutations.activityTypes.updateActivityType, {
@@ -227,7 +227,7 @@ describe("Activity type kind field", () => {
227227
}
228228
});
229229

230-
it("classifies challenge activities (completion, tiered, non-standard units)", async () => {
230+
it("classifies special activities (completion, tiered, non-standard units)", async () => {
231231
await createTestActivityType(t, challengeId, {
232232
name: "Hotel Room Workout",
233233
scoringConfig: { type: "completion", fixedPoints: 50 },
@@ -258,11 +258,11 @@ describe("Activity type kind field", () => {
258258
);
259259

260260
for (const r of result.results) {
261-
expect(r.kind).toBe("challenge");
261+
expect(r.kind).toBe("special");
262262
}
263263
});
264264

265-
it("classifies unit_based with maxPerChallenge as challenge, not core", async () => {
265+
it("classifies unit_based with maxPerChallenge as special, not core", async () => {
266266
await createTestActivityType(t, challengeId, {
267267
name: "The Max",
268268
scoringConfig: { type: "unit_based", pointsPerUnit: 25, unit: "circuits", maxUnits: 3 },
@@ -276,7 +276,7 @@ describe("Activity type kind field", () => {
276276
{ challengeId },
277277
);
278278

279-
expect(result.results[0]).toMatchObject({ name: "The Max", kind: "challenge" });
279+
expect(result.results[0]).toMatchObject({ name: "The Max", kind: "special" });
280280
});
281281

282282
it("skips rows that already have kind set", async () => {
@@ -364,7 +364,7 @@ describe("Activity type kind field", () => {
364364
Swimming: "core",
365365
"The Hunt Bonus": "bonus",
366366
Overindulge: "penalty",
367-
"The Murph": "challenge",
367+
"The Murph": "special",
368368
});
369369
});
370370
});

packages/backend/mutations/activityTypes.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const bonusThresholdsArg = v.optional(
1515
const kindArg = v.optional(
1616
v.union(
1717
v.literal("core"),
18-
v.literal("challenge"),
18+
v.literal("special"),
1919
v.literal("bonus"),
2020
v.literal("penalty"),
2121
)
@@ -251,7 +251,7 @@ export const backfillKind = mutation({
251251
}
252252

253253
const nameLower = at.name.toLowerCase();
254-
let kind: "core" | "challenge" | "bonus" | "penalty";
254+
let kind: "core" | "special" | "bonus" | "penalty";
255255

256256
if (at.isNegative) {
257257
kind = "penalty";
@@ -277,8 +277,8 @@ export const backfillKind = mutation({
277277
// Repeatable distance/duration activities = core fitness
278278
kind = "core";
279279
} else {
280-
// Everything else: completion workouts, tiered challenges, etc.
281-
kind = "challenge";
280+
// Everything else: special workouts (completion, tiered, non-standard units)
281+
kind = "special";
282282
}
283283

284284
if (!args.dryRun) {

packages/backend/mutations/apiMutations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ export const createActivityTypeForUser = internalMutation({
846846
kind: v.optional(
847847
v.union(
848848
v.literal("core"),
849-
v.literal("challenge"),
849+
v.literal("special"),
850850
v.literal("bonus"),
851851
v.literal("penalty"),
852852
)
@@ -893,7 +893,7 @@ export const updateActivityTypeForUser = internalMutation({
893893
kind: v.optional(
894894
v.union(
895895
v.literal("core"),
896-
v.literal("challenge"),
896+
v.literal("special"),
897897
v.literal("bonus"),
898898
v.literal("penalty"),
899899
)

packages/backend/schema.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ export default defineSchema({
7373
isNegative: v.boolean(),
7474
categoryId: v.optional(v.id("categories")),
7575
// Semantic classification orthogonal to categoryId (which drives Category Leader leaderboard).
76-
// core = standard fitness activities, challenge = special workouts,
77-
// bonus = system-awarded or non-competitive bonuses, penalty = negative-scoring
76+
// core = standard fitness activities, special = special workouts (streak-eligible, not in category leaderboard),
77+
// bonus = system-awarded or non-competitive bonuses (not streak-eligible), penalty = negative-scoring
7878
kind: v.optional(
7979
v.union(
8080
v.literal("core"),
81-
v.literal("challenge"),
81+
v.literal("special"),
8282
v.literal("bonus"),
8383
v.literal("penalty"),
8484
),
@@ -383,7 +383,7 @@ export default defineSchema({
383383
kind: v.optional(
384384
v.union(
385385
v.literal("core"),
386-
v.literal("challenge"),
386+
v.literal("special"),
387387
v.literal("bonus"),
388388
v.literal("penalty"),
389389
),

0 commit comments

Comments
 (0)