max14
max14
TTCTheo's Typesafe Cult
Created by max14 on 10/18/2023 in #questions
Clerk Auth with Drizzle relations
Hey, have just been watching Theo's live stream and has got me excited (for the 10th time) for restarting my side-project, I'm struggling a little on the best way to setup a relation between (and updates) between the user and my DB, so for example I want a recipe to belong to a user (which could easily be done with user Id) but I want username so it looks cleaner in the URL and in general, if a user however changes their username, how do I go about handling that?
6 replies
TTCTheo's Typesafe Cult
Created by max14 on 10/3/2023 in #questions
Redirect to Dashboard, or let user navigate themselves?
Hey, just a general UI/UX question, I have a recipes app with a home page and a dashboard (and more obvs), im not sure whether to automatically redirect the user to dashboard (if logged in) when they go to the root ("/") or to make them go to the dashboard themselves? I imagine the former, but not sure?
1 replies
TTCTheo's Typesafe Cult
Created by max14 on 9/27/2023 in #questions
ShadCn Styling / Functionality Issue
Hey all, this is a slightly unusual use case, but I've been asked to implement it, I have a list of items in a Select box, which I want to display a tooltip for each one explaining what that item is. I've tried so many combinations but can't seem to get it working, help would be much appreciated 🙂
22 replies
TTCTheo's Typesafe Cult
Created by max14 on 8/10/2023 in #questions
Use Effect causing infinite re-renders
Hey everyone, I'm a little confused on how to fix this, I'm fetching a list of engineers which I want to be able to use in a select dropdown, but when trying to map over, and set to state, its causing an infinite re-render, here is my code
function CreateTimesheetScreen({
navigation,
}: RootStackScreenProps<"CreateTimesheet">) {
const { getToken, signOut } = useAuth();
const { user } = useUser();
const [formLoading, setFormLoading] = React.useState(false);
const [engineersValue, setEngineersValue] = React.useState(null);
const [open, setOpen] = React.useState(false);
const [items, setItems] = React.useState<EngineerItem[]>([]);

const [sessionToken, setSessionToken] = React.useState("");
const [date, setDate] = React.useState(new Date());

React.useEffect(() => {
const scheduler = setInterval(async () => {
const token = await getToken();
setSessionToken(token as string);
}, 1000);

return () => clearInterval(scheduler);
}, []);

const today = new Date();

const {
control,
handleSubmit,
formState: { errors },
setValue,
setError,
} = useForm({
defaultValues: {
work_provider: "",
date_of_work: today,
order_num: "",
work_item: "",
quantity: "",
notes: "",
gang_price_split: "",
},
});

type Data = {
work_provider: string;
date_of_work: string;
order_num: string;
work_item: number;
quantity: string;
notes: string;
gang_price_split: string;
};
function CreateTimesheetScreen({
navigation,
}: RootStackScreenProps<"CreateTimesheet">) {
const { getToken, signOut } = useAuth();
const { user } = useUser();
const [formLoading, setFormLoading] = React.useState(false);
const [engineersValue, setEngineersValue] = React.useState(null);
const [open, setOpen] = React.useState(false);
const [items, setItems] = React.useState<EngineerItem[]>([]);

const [sessionToken, setSessionToken] = React.useState("");
const [date, setDate] = React.useState(new Date());

React.useEffect(() => {
const scheduler = setInterval(async () => {
const token = await getToken();
setSessionToken(token as string);
}, 1000);

return () => clearInterval(scheduler);
}, []);

const today = new Date();

const {
control,
handleSubmit,
formState: { errors },
setValue,
setError,
} = useForm({
defaultValues: {
work_provider: "",
date_of_work: today,
order_num: "",
work_item: "",
quantity: "",
notes: "",
gang_price_split: "",
},
});

type Data = {
work_provider: string;
date_of_work: string;
order_num: string;
work_item: number;
quantity: string;
notes: string;
gang_price_split: string;
};
3 replies
TTCTheo's Typesafe Cult
Created by max14 on 8/9/2023 in #questions
Expo Screen Orientation not working
Hey all, I'm having an issue where I can't get the expo-screen-orientation package to work, I've tried on a latest v iOS simulator and on the expo app via my phone, both of which won't let me lock to landscape, here is my code, would be much appreciated if you could help. I am calling this function inside a specific screen, I'm assuming this must be allowed right?
const onLoadLockToPortrait = async () => {
try {
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.LANDSCAPE_LEFT
);
} catch (error) {
console.log(error);
}
};

React.useEffect(() => {
onLoadLockToPortrait();
}, []);
const onLoadLockToPortrait = async () => {
try {
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.LANDSCAPE_LEFT
);
} catch (error) {
console.log(error);
}
};

React.useEffect(() => {
onLoadLockToPortrait();
}, []);
2 replies
TTCTheo's Typesafe Cult
Created by max14 on 8/7/2023 in #questions
Drizzle ORM schema not working
Hey all, I have a drizzle orm schema and I can't really understand the error message, could someone please help? its connected to a planetscale db scheme:
export const timesheets = mysqlTable("timesheets", {
id: serial("id").primaryKey().autoincrement(),
work_provider: varchar("work_provider", { length: 128 }),
date_of_work: timestamp("date_of_work").defaultNow(),
order_num: varchar("order_num", { length: 128 }).notNull(),
work_item: varchar("work_item", { length: 128 }).notNull(),
quantity: serial("quantity").notNull(),
notes: varchar("notes", { length: 1024 }).notNull(),
gang_price_split: varchar("gang_price_split", { length: 128 }).notNull(),
created_at: timestamp("created_at").defaultNow(),
});

export type Timesheet = InferModel<typeof timesheets>;

export const timesheetsRelations = relations(timesheets, ({ many }) => ({
engineers: many(engineers),
timesheetsToEngineers: many(timesheetsToEngineers),
}));

export const engineers = mysqlTable("engineers", {
id: serial("id").primaryKey().autoincrement(),
firstName: varchar("firstName", { length: 128 }).notNull(),
lastName: varchar("lastName", { length: 256 }).notNull(),
birthDate: varchar("birthDate", { length: 32 }).notNull(),
});

export type Engineer = InferModel<typeof engineers>;

export const engineersRelations = relations(engineers, ({ many }) => ({
timesheets: many(timesheets),
timesheetsToEngineers: many(timesheetsToEngineers),
}));

export const timesheetsToEngineers = mysqlTable(
"timesheets_to_engineers",
{
engineerId: int("engineer_id")
.notNull()
.references(() => engineers.id),
timesheetId: int("timesheet_id")
.notNull()
.references(() => timesheets.id),
},
(t) => ({
pk: primaryKey(t.engineerId, t.timesheetId),
})
);
export const timesheets = mysqlTable("timesheets", {
id: serial("id").primaryKey().autoincrement(),
work_provider: varchar("work_provider", { length: 128 }),
date_of_work: timestamp("date_of_work").defaultNow(),
order_num: varchar("order_num", { length: 128 }).notNull(),
work_item: varchar("work_item", { length: 128 }).notNull(),
quantity: serial("quantity").notNull(),
notes: varchar("notes", { length: 1024 }).notNull(),
gang_price_split: varchar("gang_price_split", { length: 128 }).notNull(),
created_at: timestamp("created_at").defaultNow(),
});

export type Timesheet = InferModel<typeof timesheets>;

export const timesheetsRelations = relations(timesheets, ({ many }) => ({
engineers: many(engineers),
timesheetsToEngineers: many(timesheetsToEngineers),
}));

export const engineers = mysqlTable("engineers", {
id: serial("id").primaryKey().autoincrement(),
firstName: varchar("firstName", { length: 128 }).notNull(),
lastName: varchar("lastName", { length: 256 }).notNull(),
birthDate: varchar("birthDate", { length: 32 }).notNull(),
});

export type Engineer = InferModel<typeof engineers>;

export const engineersRelations = relations(engineers, ({ many }) => ({
timesheets: many(timesheets),
timesheetsToEngineers: many(timesheetsToEngineers),
}));

export const timesheetsToEngineers = mysqlTable(
"timesheets_to_engineers",
{
engineerId: int("engineer_id")
.notNull()
.references(() => engineers.id),
timesheetId: int("timesheet_id")
.notNull()
.references(() => timesheets.id),
},
(t) => ({
pk: primaryKey(t.engineerId, t.timesheetId),
})
);
22 replies
TTCTheo's Typesafe Cult
Created by max14 on 7/22/2023 in #questions
Api route returns Fetch Failed
Hey, I have an api route that returns some posts, it works when I navigate to it, but when I try to request it using a RSC, it throws a Fetch Failed error, export
async function getNews() {
const res = await fetch(`${env.NEXT_PUBLIC_APP_URL}/api/news`);
if (!res.ok) {
throw new Error("Failed to fetch data");
}
return res.json();
}
async function getNews() {
const res = await fetch(`${env.NEXT_PUBLIC_APP_URL}/api/news`);
if (!res.ok) {
throw new Error("Failed to fetch data");
}
return res.json();
}
export async function GET(req: Request) {
const allPosts: Post[] = await db.select().from(posts);
return NextResponse.json(allPosts, { status: 200 });
}
export async function GET(req: Request) {
const allPosts: Post[] = await db.select().from(posts);
return NextResponse.json(allPosts, { status: 200 });
}
export default async function News() {
const news: Post[] = await getNews();
console.log(news);
return (
<div>
<h1>News</h1>
</div>
);
}
export default async function News() {
const news: Post[] = await getNews();
console.log(news);
return (
<div>
<h1>News</h1>
</div>
);
}
4 replies
TTCTheo's Typesafe Cult
Created by max14 on 7/21/2023 in #questions
Resend Email
hey, I'm created an enquiries page for people to send an email to the enquiries email address, I want to send the email from the email address they provided to my enquiries account, is this possible? this is my nextjs API route which is using Resend,
import { env } from "@/env.mjs";
import { type ErrorResponse } from "resend";
import { z } from "zod";
import { resend } from "@/lib/resend";
import EnquiryEmail from "@/components/emails/enquiry";
import { contactSchema } from "@/lib/validations/contact";

export async function POST(req: Request) {
const input = contactSchema.parse(await req.json());

try {
await resend.emails.send({
from: input.email,
to: env.EMAIL_FROM_ADDRESS,
subject: `Enquiry from ${input.firstName} ${input.lastName}`,
react: EnquiryEmail({
firstName: input.firstName,
lastName: input.lastName,
email: input.email,
phoneNumber: input.phoneNumber,
addressLine1: input.addressLine1,
cityOrTown: input.cityOrTown,
postcode: input.postcode,
enquiry: input.enquiry,
}),
});

return new Response(null, { status: 200 });
} catch (error) {
console.error(error);

if (error instanceof z.ZodError) {
return new Response(error.message, { status: 422 });
}

const resendError = error as ErrorResponse;

if (resendError?.error?.message) {
return new Response(resendError.error.message, { status: 429 });
}

if (error instanceof Error) {
return new Response(error.message, { status: 500 });
}

return new Response("Something went wrong", { status: 500 });
}
}
import { env } from "@/env.mjs";
import { type ErrorResponse } from "resend";
import { z } from "zod";
import { resend } from "@/lib/resend";
import EnquiryEmail from "@/components/emails/enquiry";
import { contactSchema } from "@/lib/validations/contact";

export async function POST(req: Request) {
const input = contactSchema.parse(await req.json());

try {
await resend.emails.send({
from: input.email,
to: env.EMAIL_FROM_ADDRESS,
subject: `Enquiry from ${input.firstName} ${input.lastName}`,
react: EnquiryEmail({
firstName: input.firstName,
lastName: input.lastName,
email: input.email,
phoneNumber: input.phoneNumber,
addressLine1: input.addressLine1,
cityOrTown: input.cityOrTown,
postcode: input.postcode,
enquiry: input.enquiry,
}),
});

return new Response(null, { status: 200 });
} catch (error) {
console.error(error);

if (error instanceof z.ZodError) {
return new Response(error.message, { status: 422 });
}

const resendError = error as ErrorResponse;

if (resendError?.error?.message) {
return new Response(resendError.error.message, { status: 429 });
}

if (error instanceof Error) {
return new Response(error.message, { status: 500 });
}

return new Response("Something went wrong", { status: 500 });
}
}
6 replies
TTCTheo's Typesafe Cult
Created by max14 on 2/5/2023 in #questions
Image upload for MongoDB?
Hey all, I currently have a MongoDB which I store recipes, users and user sessions, I am implementing a recipe image that the user can upload on creation (or after), it doesn't seem like mongodb is good for images, what would anyone recommend for implementing a recipe image upload?
3 replies
TTCTheo's Typesafe Cult
Created by max14 on 2/1/2023 in #questions
Options of Video Chat APIs to use inside my NextJS app
Hey, I'm building an app which I want to include video chat, I don't think its very feasible to build and host my own video chat API (at least for the time being), anyone have any recommendations of Video Chat APIs, I would prefer consistency/reliability over video quality.
3 replies
TTCTheo's Typesafe Cult
Created by max14 on 1/28/2023 in #questions
Anyone have any opinions on using Vitest or Jest for testing a NextJS + TS app?
Hey, Im building a Nextjs app with TS, NextAuth and Prisma. Just wondering if anyone has used Vitest and Jest in production and could give their opinion on them?
1 replies
TTCTheo's Typesafe Cult
Created by max14 on 12/18/2022 in #questions
Safe to use a DB item Id inside url?
Hey, was just wondering if its secure to use a database object id (for example /recipe/639b9e04c57c616a5e738asd) inside the url?
23 replies