jairrard
jairrard
TTCTheo's Typesafe Cult
Created by jairrard on 9/26/2024 in #questions
Resizing, snapping and drag and drop
If you were to build something like the clip below, what would you use, if any library at all? I was at first thinking of building it myself but there are quite a few edge cases so thought it might be worth looking at a library. I've used dnd-kit for most of the drag and drop but it doesn't have resizing. Any recs for React?
3 replies
TTCTheo's Typesafe Cult
Created by jairrard on 6/3/2024 in #questions
Dynamic breadcrumbs
In my app, you can only access a project on the route /projects/:projectId. You can get to this route from /customers/:customerId and from /projects. I want the breadcrumbs in /projects/:projectId to show which path I actually came from so that the navigation makes sense. I am using react router v6. How would you achieve this? I'm thinking of creating a breadcrumbs context which updates a breadcrumbs state whenever I am navigating. In the project page, I will then consume this context and check the state to display the right breadcrumb. Not sure if this is the best approach since I need to now manage this breadcrumbs context every time I am navigating... What is the recommended solution? I am guessing this is a common requirement..
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 5/31/2024 in #questions
useLayoutEffect vs useEffect (with a setTimeout)
I am conditionally rendering a list of input elements. I want to give the first element focus when they are rendered. I added refs to the inputs and a useEffect where I focus on the respective ref (when the change happens). Adding refs to the input -
// inside the map
<input
ref={(el) => {optionRefs.current[index] = el;}}
/>
// inside the map
<input
ref={(el) => {optionRefs.current[index] = el;}}
/>
My useEffect -
useEffect(() => {
if (
(type === "select" || type === "multi-select") &&
optionRefs.current[0]
) {
optionRefs.current[0]?.focus();
}
}, [type]);
useEffect(() => {
if (
(type === "select" || type === "multi-select") &&
optionRefs.current[0]
) {
optionRefs.current[0]?.focus();
}
}, [type]);
However, this doesn't work because the input component isn't rendered when it is trying to focus on the ref. GPT recommended I add a setTimeout -
useEffect(() => {
if (
(type === "select" || type === "multi-select") &&
optionRefs.current[0]
) {
setTimeout(() => {
optionRefs.current[0]?.focus();
}, 0);
}
}, [type]);
useEffect(() => {
if (
(type === "select" || type === "multi-select") &&
optionRefs.current[0]
) {
setTimeout(() => {
optionRefs.current[0]?.focus();
}, 0);
}
}, [type]);
And this works! This isn't best practice though so I looked at what is and it seems to be useLayoutEffect. When I tried the first approach with it, I wasn't successful. What am I doing wrong here?
4 replies
TTCTheo's Typesafe Cult
Created by jairrard on 4/23/2024 in #questions
filtering, sorting and grouping + pagination
I want to be able to filter, group and sort tasks. Given tasks are ever expanding, there is also a need for pagination. Are there any production examples of filtering, grouping and sorting + pagination? I am struggling to understand what shape the initial response should look like, how the cache should be constructed for each group, and how to refetch or load more just for a specific group. I haven't even gotten to optimistic updates as yet..
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 3/27/2024 in #questions
Building an application with multiple logged in accounts and multiple workspaces per account
My web app requires the ability to be logged into multiple accounts and the ability to have multiple workspaces per account. I haven't ever set this up before in my web apps and so was wondering if anyone had experience in this. My main questions - 1. What is the recommended state management to know which logged in user is the active user? 2. Any advice on routing?
4 replies
TTCTheo's Typesafe Cult
Created by jairrard on 1/24/2024 in #questions
refreshing access token manually in axios
In my axios API calls, I need to give an Authorization header with the access token -
const res = await axios.get(
`https://us-east-1.aws.data.mongodb-api.com/app/${process.env.REACT_APP_APP_ID}/endpoint/taskLogs`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
},
params: {
taskId,
},
}
);
const res = await axios.get(
`https://us-east-1.aws.data.mongodb-api.com/app/${process.env.REACT_APP_APP_ID}/endpoint/taskLogs`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
},
params: {
taskId,
},
}
);
Question - How should I ideally be handling this refreshing of the access token? What I am doing right now - Using a useAccessToken hook as follows -
import { useRealmApp } from "src/store/RealmApp";
import { decodeJwt } from "jose";

export const useAccessToken = () => {
const app = useRealmApp();
const getValidAccessToken = async (): Promise<string | null> => {
const accessToken = app.currentUser?.accessToken;
const payload = decodeJwt(accessToken);
if (payload.exp) {
const isExpired = payload.exp * 1000 < Date.now();
if (isExpired) {
// refresh the custom data which will also refresh the access token
await app.currentUser?.refreshCustomData();
return app.currentUser?.accessToken;
} else {
return accessToken;
}
} else {
console.log("Failed to decode the access token");
}
return null;
};

return getValidAccessToken;
};
import { useRealmApp } from "src/store/RealmApp";
import { decodeJwt } from "jose";

export const useAccessToken = () => {
const app = useRealmApp();
const getValidAccessToken = async (): Promise<string | null> => {
const accessToken = app.currentUser?.accessToken;
const payload = decodeJwt(accessToken);
if (payload.exp) {
const isExpired = payload.exp * 1000 < Date.now();
if (isExpired) {
// refresh the custom data which will also refresh the access token
await app.currentUser?.refreshCustomData();
return app.currentUser?.accessToken;
} else {
return accessToken;
}
} else {
console.log("Failed to decode the access token");
}
return null;
};

return getValidAccessToken;
};
Not at all sure if this is what the recommended way is (for example - using a library like jose or an equivalent to decode the jwt). Would really appreciate some confirmation before I make changes in all my tanstack query hooks!
5 replies
TTCTheo's Typesafe Cult
Created by jairrard on 1/24/2024 in #questions
Error boundaries
I am using typescript and so never usually have the situation where a field is accessed on an undefined object. However, I recently had the situation where it was and my user was faced with a blank white screen. How can I catch these errors with an error boundary? Should I be applying the error boundary on the entire app? Never really used it before and it seems to be a legacy API. Is this how peopel still handle it?
7 replies
TTCTheo's Typesafe Cult
Created by jairrard on 12/4/2023 in #questions
shadcn ui combobox does not show "No results" when no options given
No description
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 11/16/2023 in #questions
dndkit dragging tables - losing mouse pointer because I am collapsing the rows onDragStart
I have several tables which need to have drag and drop for reordering. These tables are large and it is tedious to drag them over each other. It would be cool to have the tables collapse when the drag starts and expand when the drag ends. However, when before the drag starts the drag handle icon is in one place and when it starts it is in a different place (due to the collapsing of the tables). Is there any way I can move the pointer to the position of the drag handle once the drag starts?
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 11/16/2023 in #questions
should localstorage be cleared on logout?
I'm using MongoDB App Services (Realm) for auth. Just something I'm kinda stuck with for now. I faced an issue where something I set in localstorage persists for the next user. Wasn't sure if I should clear the entire localstorage on logout or just the things I set.
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 11/14/2023 in #questions
Radix Popover inside Radix Dialog not working
Trying to use a popper inside a dialog. the popper shows up inside the dialog but I am not able to click on anything inside the popper. It is acting as if the popper were not there with the cursor changing as per the elements behind the popper. Any idea what could be happening?
4 replies
TTCTheo's Typesafe Cult
Created by jairrard on 11/14/2023 in #questions
Using Radix Select with objects
I am creating a Select component with Radix. I wanted to select from an array of objects of type {unit: "minute" | "hour", value:number}. Seems like value always needs to be a string though. What I'm thinking of doing -
<Select
value={
taskTemplateCtx.state.estimate.value + " " +
taskTemplateCtx.state.estimate.unit
}
onValueChange={(value) => {
const e = estimateOptions.find(
(estimate) => estimate.value + " " + estimate.unit === value
);
if (e)
taskTemplateCtx.dispatch({
type: "estimate_update",
estimate: e,
});
}}
>
<SelectTrigger className="w-fit gap-2">
<ClockIcon className="h-4 w-4 text-gray-700" />
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{/* <SelectLabel>Fruits</SelectLabel> */}
{estimateOptions.map((estimate) => (
<SelectItem
value={estimate.value + " " + estimate.unit}
>
{estimate.value +
" " +
(estimate.unit === "minute" ? "min" : "hr")}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Select
value={
taskTemplateCtx.state.estimate.value + " " +
taskTemplateCtx.state.estimate.unit
}
onValueChange={(value) => {
const e = estimateOptions.find(
(estimate) => estimate.value + " " + estimate.unit === value
);
if (e)
taskTemplateCtx.dispatch({
type: "estimate_update",
estimate: e,
});
}}
>
<SelectTrigger className="w-fit gap-2">
<ClockIcon className="h-4 w-4 text-gray-700" />
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{/* <SelectLabel>Fruits</SelectLabel> */}
{estimateOptions.map((estimate) => (
<SelectItem
value={estimate.value + " " + estimate.unit}
>
{estimate.value +
" " +
(estimate.unit === "minute" ? "min" : "hr")}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
Does this make sense? Feels wrong ..
4 replies
TTCTheo's Typesafe Cult
Created by jairrard on 11/12/2023 in #questions
shadcn/ui combobox with objects
I am creating a Combobox based on shadcn/ui (https://ui.shadcn.com/docs/components/combobox) which uses cmdk (https://github.com/pacocoursey/cmdk), Popover and Dialog from Radix under the hood. The implementation in the docs uses the value of each <CommandItem> to filter. However, all my use cases are with objects with id and name keys where name is not unique. How should I be handling the filtering and onSelect ? My solution was to give id as the value and then add my own filter for <Command> as follows -
<Command
filter={(value, search) => {
const obj = myArrayOfObjects.find(
(stageTemplate) => stageTemplate._id.toString() === value
);
if (obj) {
if (
stageTemplate.name.toLowerCase().includes(search.toLowerCase())
)
return 1;
}
return 0;
}}
>
<Command
filter={(value, search) => {
const obj = myArrayOfObjects.find(
(stageTemplate) => stageTemplate._id.toString() === value
);
if (obj) {
if (
stageTemplate.name.toLowerCase().includes(search.toLowerCase())
)
return 1;
}
return 0;
}}
>
For the onSelect I have the following -
onSelect={(currentValue: string) => {
const obj = myArrayOfObjects.find((objs) => obj.id === currentValue);
if (obj) {
// handle on select
}
setOpen(false);
}}
onSelect={(currentValue: string) => {
const obj = myArrayOfObjects.find((objs) => obj.id === currentValue);
if (obj) {
// handle on select
}
setOpen(false);
}}
Does this make sense? Don't love that I am using Array.find() for each element to decide if it should be filtered out or not.
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 9/7/2023 in #questions
Building an in-app chat
I am building a task management tool where different companies can collaborate. In order to enable conversations, I am creating a chat functionality. This includes - chats with multiple people, @mentions in messages to entities (like people or files) and being able to keep track of an unread messages count per user. Has anyone worked on something similar? Not quite sure where to start..
2 replies
TTCTheo's Typesafe Cult
Created by jairrard on 7/5/2023 in #questions
Same side panel on different routes
I have an app where I'm dealing with different kinds of tasks. Whenever I click on a task, I need a side panel to open up where I can edit the task. I need the same panel on routes /a/b/c as well as /d/e. What would be the most general way to build such a panel and activate it?
10 replies
TTCTheo's Typesafe Cult
Created by jairrard on 4/22/2023 in #questions
how tight should types be?
I have a tasker field in my task type. The most "accurate" type would look like -
type tasker =
{
_id: ObjectId;
name: string;
email: string;
}
| {
email: string;
}
| {
persona: string;
};
type tasker =
{
_id: ObjectId;
name: string;
email: string;
}
| {
email: string;
}
| {
persona: string;
};
However, I get errors like Property '_id' does not exist on type '{ email: string; }'. even after I am checking as follows if (tasker._id) {}. This is quite annoying and tbh I am not even sure how to get around it. On the other hand I could type tasker in the following way -
type tasker =
{
_id?: ObjectId;
name?: string;
email?: string;
persona?: string
}
type tasker =
{
_id?: ObjectId;
name?: string;
email?: string;
persona?: string
}
but this doesn't feel right. What should I be doing?
12 replies
TTCTheo's Typesafe Cult
Created by jairrard on 4/22/2023 in #questions
Setting up notifications in a serverless infrastructure.
My backend is using MongoDB & serverless. Frontend is using tanstack query. What I am doing currently - 1. Listening to a websocket (at wss://websockets.company.com/and if there is a notification, I do the following - 1.a. Invalidate my notifications query 1.b. Look at the event that was just heard at the websocket and parse it for the alert I want to give (eg - if the event looked like {type: "task", action "completed", _id: "123"} I would give an alert that a task was completed in a snackbar and invalidate that task query) Questions - 1. How should I be setting up hearing for notifications? Is 1.a fine? 2. What should the format for the notification be? Is there a standard? Since there will be many notifications over time, I'd love some advice on what is the best way to set this up. Currently mine just looks like a massive switch case / if-else block.
1 replies
TTCTheo's Typesafe Cult
Created by jairrard on 4/7/2023 in #questions
div inside a div - preventing complex onClick event propagation
I currently have the following component -
<div onClick={() => { // redirect to some other route }}>
<div onClick={(e) => { e.stopPropagation(); setIsMenuOpen(true) }}>
<Menu open={isMenuOpen} />
</div>
</div>
<div onClick={() => { // redirect to some other route }}>
<div onClick={(e) => { e.stopPropagation(); setIsMenuOpen(true) }}>
<Menu open={isMenuOpen} />
</div>
</div>
The first click works fine - the menu opens as it should without the parent div onClick going through. However, even though I do have e.stopPropagation(), when I click on an option in the menu or anywhere else on the page, the parent div onClick still goes through after. How can I stop this?
6 replies
TTCTheo's Typesafe Cult
Created by jairrard on 4/5/2023 in #questions
Routing patterns
Context My app has a thing called spaces where you can access multiple tabs like "Tasks", "Journeys", etc. The route for a space is /spaces/:id. I am using headless UI tabs to show the different tabs in a space. As of now I do not have a route defined for each tab. I did not foresee the need to be able to go to a tab directly through navigation but I now need to. For example, I need to be able to go to a space and in the space to the journey tab (which is the second tab) directly from somewhere else. The default behavior is to render the first tab as the selected tab. I am using react router as of now (have not made a switch to Next as yet). Questions 1. Should I be creating the route as /spaces/:id/:tab and then look at the query param and set the tab accordingly? 2. In the journeys tab, clicking on a journey should take them to that journey which would need its own page. How should I be handling this routing? Should I create a spaces/:id/journeys/:journeyId route? Or should I create a /journeys/:journeyId route? What is recommended?
1 replies
TTCTheo's Typesafe Cult
Created by jairrard on 3/21/2023 in #questions
Type for request and response. Should they be shared?
Let's say I have 2 apis - getTask and createTask For createTask I need the request to be of the type -
{
title: string,
description: string,
dueDate: Date
journeyId: ObjectId
}
{
title: string,
description: string,
dueDate: Date
journeyId: ObjectId
}
For getTask, the response is of the type -
{
_id: ObjectId,
journey: {
_id: ObjectId,
name: string
},
dueDate: Date,
createdAt: Date,
updatedAt: Date,
}
{
_id: ObjectId,
journey: {
_id: ObjectId,
name: string
},
dueDate: Date,
createdAt: Date,
updatedAt: Date,
}
Questions - 1. Should I be using 2 different types or try to create one parent type from which I use a Partial type for the createTask request? If so, there would be issues with journeyId (in request) and journey (in response) where they should ideally be part of one field in both types rather than having 2 fields which refer to the same thing. 2. If 1 is a depends on, what would it depend on? Also for some context - I am using Mongodb with api calls being made via Mongodb App Services (Realm). I am looking to move over to the T3 stack soon.
5 replies