Skip to content

Feature/116 webinars backend - #122

Open
achneerov wants to merge 2 commits into
developfrom
feature/116-webinars-backend
Open

Feature/116 webinars backend#122
achneerov wants to merge 2 commits into
developfrom
feature/116-webinars-backend

Conversation

@achneerov

@achneerov achneerov commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Closes #116

Overview

Make webinars table in DB (was already done) and backend actions (also added schema evaluation in zod)

Testing

Made a dummy page and tested all three endpoints create, modify and delete.

Screenshots / Screencasts

none

Checklist

  • Code is neat, readable, and works
  • Code is commented where appropriate and well-documented
  • Commit messages follow our guidelines
  • Issue number is linked
  • Branch is linked
  • Reviewers are assigned (one of your tech leads)

Tip: You can make the issue and then check them after the fact or replace [ ] with [x] to check it!

@martin0024 martin0024 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good pr alex

webinar_id: z.string().uuid("Invalid webinar"),
});

export function parseBooleanField(value: FormDataEntryValue | null): boolean {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the parseBooleanField

tier: webinarTierSchema,
duration_minutes: durationSchema,
youtube_url: youtubeUrlSchema.optional(),
is_active: z.boolean().default(true),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
is_active: z.boolean().default(true),
is_active: z.enum(["true", "false"]).optional(),

tier: webinarTierSchema.optional(),
duration_minutes: durationSchema.optional(),
youtube_url: z.union([youtubeUrlSchema, z.literal("")]).optional(),
is_active: z.boolean().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
is_active: z.boolean().optional(),
is_active: z.enum(["true", "false"]).optional(),

tier: field(formData, "tier"),
duration_minutes: field(formData, "duration_minutes"),
youtube_url: field(formData, "youtube_url") || undefined,
is_active: formData.has("is_active")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
is_active: formData.has("is_active")
is_active: field(formData, "is_active"),

tier: parsed.data.tier,
durationMinutes: parsed.data.duration_minutes,
youtubeUrl: parsed.data.youtube_url || null,
isActive: parsed.data.is_active,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
isActive: parsed.data.is_active,
isActive: parsed.data.is_active !== "false",

patch.youtubeUrl = parsed.data.youtube_url || null;
}
if (parsed.data.is_active !== undefined) {
patch.isActive = parsed.data.is_active;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
patch.isActive = parsed.data.is_active;
patch.isActive = parsed.data.is_active === "true";

Comment on lines +170 to +173
const deleted = await db
.delete(webinars)
.where(eq(webinars.id, parsed.data.webinar_id))
.returning({ id: webinars.id });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const deleted = await db
.delete(webinars)
.where(eq(webinars.id, parsed.data.webinar_id))
.returning({ id: webinars.id });
let deleted;
try {
deleted = await db
.delete(webinars)
.where(eq(webinars.id, parsed.data.webinar_id))
.returning({ id: webinars.id });
} catch (error) {
console.error(error);
return { errors: { _form: ["Could not delete webinar"] } };
}

Comment on lines +138 to +146
try {
await db
.update(webinars)
.set(patch)
.where(eq(webinars.id, parsed.data.webinar_id));
} catch (error) {
console.error(error);
return { errors: { _form: ["Could not update webinar"] } };
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try {
await db
.update(webinars)
.set(patch)
.where(eq(webinars.id, parsed.data.webinar_id));
} catch (error) {
console.error(error);
return { errors: { _form: ["Could not update webinar"] } };
}
const updated = await db
.update(webinars)
.set(patch)
.where(eq(webinars.id, parsed.data.webinar_id))
.returning({ id: webinars.id });
if (!updated.length) return { errors: { _form: ["Webinar not found"] } };

Comment on lines +110 to +118
const [existing] = await db
.select({ id: webinars.id })
.from(webinars)
.where(eq(webinars.id, parsed.data.webinar_id))
.limit(1);

if (!existing) {
return { errors: { _form: ["Webinar not found"] } };
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove it

Suggested change
const [existing] = await db
.select({ id: webinars.id })
.from(webinars)
.where(eq(webinars.id, parsed.data.webinar_id))
.limit(1);
if (!existing) {
return { errors: { _form: ["Webinar not found"] } };
}

Comment on lines +5 to +23
const youtubeUrlSchema = z
.string()
.url("Enter a valid YouTube URL")
.refine(
(value) => {
try {
const hostname = new URL(value).hostname.toLowerCase();
return [
"youtube.com",
"www.youtube.com",
"youtu.be",
"www.youtu.be",
].includes(hostname);
} catch {
return false;
}
},
{ message: "URL must be a YouTube URL" },
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const youtubeUrlSchema = z
.string()
.url("Enter a valid YouTube URL")
.refine(
(value) => {
try {
const hostname = new URL(value).hostname.toLowerCase();
return [
"youtube.com",
"www.youtube.com",
"youtu.be",
"www.youtu.be",
].includes(hostname);
} catch {
return false;
}
},
{ message: "URL must be a YouTube URL" },
);
const youtubeUrlSchema = z
.string()
.url("Enter a valid YouTube URL")
.refine(
(value) => {
const hostname = new URL(value).hostname.toLowerCase();
return [
"youtube.com",
"www.youtube.com",
"youtu.be",
"www.youtu.be",
].includes(hostname);
},
{ message: "URL must be a YouTube URL" },
);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dude I tried that before and it lowkey crashes because if const hostname = new URL(value).hostname.toLowerCase(); fails then this crashes:
return [
"youtube.com",
"www.youtube.com",
"youtu.be",
"www.youtu.be",
].includes(hostname);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants