Rigrig
Rigrig
TTCTheo's Typesafe Cult
Created by Rigrig on 3/4/2024 in #questions
Enabling offline mode with the t3 stack
I'm using the t3 stack with trpc and prisma. The application I'm building is for use on construction sites who need a cached version of their data when their wifi is patchy. I want to keep using the stack i'm currently using but let users have access to their information if the wifi is sketchy which syncs to the database when wifi is established. The application doesn't hold alot of data - maybe 50-200 rows of 2-3 sql tables. Options I've considered 1. Using the persistance features in client state management libraries (e.g. zustand) 2. Using a tool that keeps a local SQLite db in sync with a server db e.g. WatermelonDB, ElectricDB, powersync The first option seems straight forward but will need some custom code to manage the sync when wifi is re established - the second looks more fit for purpose but requires I drop prisma and use the libraries ORM or raw SQL (I'm not comfortable dropping prisma) Thoughts?
3 replies
TTCTheo's Typesafe Cult
Created by Rigrig on 12/6/2023 in #questions
Help with type safe trpc fetch call
webdev newbie here. I have a trpc procedure that fetches some json. I want to validate it and have tRPC throw an error if the data isn't structured correctly which i use it. I'm trying to make it type safe but this is the best i can come up with. I'm trying to understand some of the type errors if i do it different. 1. Why do I need to validate the data twice? this code validates the rawData then it validates it again in the .output(). Doesn't this make the .output() code redundant? I'm repeating the same .array() and rowSchema in 2 places. Is there a more maintainable way to write this? 2. The implemetatio of 'unkown' type feels messy. Is there an altenative type you would typically use here? I've tried Row[] but with no joy.
import { z } from "zod";
import { rowSchema, type Row } from "~/schema";

import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";

export const tableRouter = createTRPCRouter({
rowData: publicProcedure.output(z.array(rowSchema)).query(async () => {
const response = await fetch(
"https://www.ag-grid.com/example-assets/space-mission-data.json",
);
const rawData: unknown = await response.json();
const validatedData = rowSchema.array().parse(rawData);
return validatedData;
}),
});
import { z } from "zod";
import { rowSchema, type Row } from "~/schema";

import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";

export const tableRouter = createTRPCRouter({
rowData: publicProcedure.output(z.array(rowSchema)).query(async () => {
const response = await fetch(
"https://www.ag-grid.com/example-assets/space-mission-data.json",
);
const rawData: unknown = await response.json();
const validatedData = rowSchema.array().parse(rawData);
return validatedData;
}),
});
3 replies
TTCTheo's Typesafe Cult
Created by Rigrig on 11/5/2023 in #questions
Is anyone using the nextjs app router for their frontend and pages for trpc?
If you could share an example repo I'd love to see how you've implemented this
5 replies
TTCTheo's Typesafe Cult
Created by Rigrig on 11/5/2023 in #questions
Making all my components 'use client' while maintaining protectedProcedures
Hi. I'm using the full T3 stack with prisma, next auth, and nextjs with the app router. I want to simplify my developer experience while i learn the ropes by make all my components a 'use client' component. However - I'll be using live data so I'll be using protectedProcedures throughout my app. My question is, is there an equivalent to getServerAuthSession() for checking the session status on the client side? For example, I want to add 'use client' to the top of this file and change the api import to '@/trpc/react' so I can add interactivity directly inside the component without trying to figure out how to do the it the server rendered way. //page.tsx (server component)
//imports go here

const Page = () => {
return (
<main className="flex h-screen justify-center">
<div className="h-full w-full max-w-md border-x border-slate-400">
<div>Todos:</div>
<Todos />
</div>
</main>
);
};

export default Page;

const Todos = async () => {
const session = await getServerAuthSession();
if (!session?.user) return <div>Sign in to see your todos</div>;

const todos = await api.todo.getTodos.query();

return (
<div>
{todos.map((todo) => (
<div key={todo.id} className="w-full">
<TodoItem id={todo.id} />
</div>
))}
</div>
);
};
//imports go here

const Page = () => {
return (
<main className="flex h-screen justify-center">
<div className="h-full w-full max-w-md border-x border-slate-400">
<div>Todos:</div>
<Todos />
</div>
</main>
);
};

export default Page;

const Todos = async () => {
const session = await getServerAuthSession();
if (!session?.user) return <div>Sign in to see your todos</div>;

const todos = await api.todo.getTodos.query();

return (
<div>
{todos.map((todo) => (
<div key={todo.id} className="w-full">
<TodoItem id={todo.id} />
</div>
))}
</div>
);
};
//todo-item.tsx (client component)
"use client";
//imports go here

export const TodoItem = ({ id }: { id: string }) => {
const todo = api.todo.getTodoById.useQuery({ id: id });

return (
<div className="m-4 flex items-center justify-between">
<div className="flex gap-2">
<Checkbox
id="title"
onCheckedChange={() => {
console.log(`change: ${id}`);
}}
/>
<Label htmlFor="title">{todo.data?.title}</Label>
</div>
<Button asChild>
<Link href={`/todo/${id}`}>Edit</Link>
</Button>
</div>
);
};
"use client";
//imports go here

export const TodoItem = ({ id }: { id: string }) => {
const todo = api.todo.getTodoById.useQuery({ id: id });

return (
<div className="m-4 flex items-center justify-between">
<div className="flex gap-2">
<Checkbox
id="title"
onCheckedChange={() => {
console.log(`change: ${id}`);
}}
/>
<Label htmlFor="title">{todo.data?.title}</Label>
</div>
<Button asChild>
<Link href={`/todo/${id}`}>Edit</Link>
</Button>
</div>
);
};
2 replies