Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
367775f
easy fix
LNorman8 Jun 20, 2026
284fc08
Set granularity in first render
LNorman8 Jun 20, 2026
b3c82af
Just commenting these two out.
LNorman8 Jun 20, 2026
7680935
Again, I don't see any effect from removing this.
LNorman8 Jun 20, 2026
b0bd918
Nothing outside of the `LayoutEffect` sets any of those three values,…
LNorman8 Jun 20, 2026
3a2557d
low hanging fruit
LNorman8 Jun 20, 2026
ce5a271
Medium Hanging Fruit
LNorman8 Jun 20, 2026
0d311d7
Medium Hanging Fruit but I might be misunderstanding why we were tryi…
LNorman8 Jun 20, 2026
030fd87
Revert "Medium Hanging Fruit but I might be misunderstanding why we w…
LNorman8 Jun 21, 2026
0ed66a4
Merge branch 'dev' into eslint-setState
LNorman8 Jun 21, 2026
01961bf
run formatter :(
LNorman8 Jun 21, 2026
0d447f4
Feature/added mobile dontate button to main header (#435) (#442)
roguediv Jun 23, 2026
3f411c0
updated the linter and fixed a couple linter errors (#452)
roguediv Jun 23, 2026
363f3e4
ran prettier (#452)
roguediv Jun 23, 2026
9b241a1
Merge branch 'dev' into eslint-setState
LNorman8 Jun 23, 2026
9a0bbcb
Why did the merge do that.
LNorman8 Jun 23, 2026
b083f99
Fixed 2 `preserve-manual-memoization` errors.
LNorman8 Jun 23, 2026
96296c6
Manually ignore each instance of `set-state-in-effect` rather than gl…
LNorman8 Jun 23, 2026
94ac242
Set max warnings to 0.
LNorman8 Jun 23, 2026
57dfab1
6
LNorman8 Jun 23, 2026
2d8147d
5
LNorman8 Jun 23, 2026
247b7f5
4
LNorman8 Jun 23, 2026
b2cb869
Merge branch 'dev' into eslint-setState
LNorman8 Jul 2, 2026
17b026f
Ok merge issues fixed
LNorman8 Jul 2, 2026
fa1b7fd
Merge remote-tracking branch 'origin/dev' into eslint-setState
LNorman8 Jul 21, 2026
c6aab25
8 problems. 7 set-state, one immutability with `window.location.href`…
LNorman8 Jul 21, 2026
eb11da4
Last little bits of cleanup (i think)
LNorman8 Jul 25, 2026
b899073
Now actually got through all of the comments
LNorman8 Jul 25, 2026
7f3e1ec
Remove illegal assignment to href
LNorman8 Jul 25, 2026
b0abee1
Directly update user in render rather than as part of effect. Other o…
LNorman8 Jul 25, 2026
f8656ce
prettier hates semicolons now?
LNorman8 Jul 25, 2026
de691fd
5 left.
LNorman8 Jul 25, 2026
de78f6f
Revert "5 left."
LNorman8 Jul 27, 2026
2f32d24
Merge remote-tracking branch 'origin/dev' into eslint-setState
LNorman8 Jul 27, 2026
8731445
4
LNorman8 Jul 27, 2026
5fbaebb
3
LNorman8 Jul 27, 2026
2e21436
2
LNorman8 Jul 27, 2026
0c16941
1
LNorman8 Jul 27, 2026
4772b60
Remembered Prettier
LNorman8 Jul 27, 2026
0a7795a
0!
LNorman8 Jul 27, 2026
ad27c1a
Remembered Prettier :(
LNorman8 Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ node_modules/
#misc
.direnv
shell.nix
.eslintcache
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
.next/
pnpm-lock.yaml
node_modules/
public/images/
22 changes: 13 additions & 9 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,22 @@ export default defineConfig([
},
{
rules: {
// Show stoppers
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-call': 'error',

// Keep track of
'object-shorthand': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
'@typescript-eslint/no-unsafe-call': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'@typescript-eslint/no-unsafe-enum-comparison': 'warn',
'react-hooks/set-state-in-effect': 'warn', // Should go back to (default) error when current set are dealt with
'tailwindcss/no-custom-classname': 'off',
'react-hooks/set-state-in-effect': 'off', //temp
'react-hooks/preserve-manual-memoization': 'off', //temp
'react-hooks/refs': 'off', //temp
'react-hooks/immutability': 'off', //temp

// React Compiler rules (for testing)
'react-hooks/refs': 'warn',
'react-hooks/immutability': 'warn',
},
},
{
Expand Down
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@
"overrides": {
"@babel/runtime@<7.26.10": ">=7.26.10",
"undici@>=6.0.0 <6.21.2": ">=6.21.2"
}
},
"onlyBuiltDependencies": [
"esbuild",
"sharp",
"unrs-resolver"
]
}
}
2 changes: 1 addition & 1 deletion src/app/account/AccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function AccountPage() {
loggedInUser.data &&
loggedInUser.data.onboardingStage != OnboardingStage.JOINED
) {
window.location.href = '/volunteer'
window.location.assign('/volunteer')
return null
}

Expand Down
27 changes: 18 additions & 9 deletions src/app/account/sections/AccountDetailsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { zDiscordUserIsInServerResponse } from '@/contracts/responses'
import { useFetch } from '@/util/hooks'
import { skipToken, useQuery } from '@tanstack/react-query'
import cx from 'classnames'
import { ChangeEvent, FormEvent, useEffect, useState } from 'react'
import { ChangeEvent, FormEvent, useState } from 'react'
import { IoClose } from 'react-icons/io5'

interface AccountDetailsSectionProps {
Expand All @@ -35,8 +35,9 @@ export function AccountDetailsSection({
onSave,
donorLinkError,
onDonorLinkSubmit,
}: AccountDetailsSectionProps) {
}: Readonly<AccountDetailsSectionProps>) {
const { ready, onGet } = useFetch()
const [lastUserData, setLastUserData] = useState(userData)
const [updatedUser, setUpdatedUser] = useState(userData)
const discordUserId = userData.discordUsers?.[0]?.id ?? null

Expand All @@ -53,9 +54,10 @@ export function AccountDetailsSection({
: skipToken,
})

useEffect(() => {
if (lastUserData !== userData) {
setUpdatedUser(userData)
}, [userData])
setLastUserData(userData)
}

const membershipDeliverableLabels: Record<
MembershipDeliverableStatus,
Expand Down Expand Up @@ -168,10 +170,17 @@ export function AccountDetailsSection({
shirtSize: userData.shirtSize ?? null,
})
const userHasDonor = !!userData.donors?.length

useEffect(() => {
if (!pendingLinkEmail) return

const [prevUserAddress, setPrevUserAddress] = useState(userData.address)
const [prevUserDonors, setPrevUserDonors] = useState(userData.donors)

// Possibly deprecated - pendingLinkEmail is only set within this statement, which will never run with it's default value
if (
pendingLinkEmail &&
(userData.address !== prevUserAddress ||
userData.donors !== prevUserDonors)
) {
setPrevUserAddress(userData.address)
setPrevUserDonors(userData.donors)
const matchedDonor = userData.donors?.find(
(donor) => normalizeEmail(donor.email) === pendingLinkEmail
)
Expand All @@ -188,7 +197,7 @@ export function AccountDetailsSection({
setShowDonorLinkForm(false)
setShowAddressConfirmModal(true)
setPendingLinkEmail(null)
}, [pendingLinkEmail, userData.address, userData.donors])
}

const handleChangeDonorEmail = (e: ChangeEvent<HTMLInputElement>) => {
setDonorLinkForm({
Expand Down
8 changes: 4 additions & 4 deletions src/app/admin/layout/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,10 @@ function PageSelect({
if (0 <= newPage && newPage <= maxPage) onChange(newPage)
else setValue((page + 1).toString())
}

useEffect(() => {
setValue((page + 1).toString())
}, [page])
const pageStr = (page + 1).toString()
if (value != pageStr) {
setValue(pageStr)
}

useEffect(() => {
if (page < 0) onChange(0)
Expand Down
1 change: 0 additions & 1 deletion src/app/admin/panels/fundraising/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,6 @@ export default function Page() {
if (inclusiveRangeMs < oneDayMs) {
return
}

applyChartViewOverrideRange({
start,
end,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { SortDirection } from '@/contracts/requests'
import { useActblueQueries } from '@/queries'
import { keepPreviousData, useQueries, useQuery } from '@tanstack/react-query'
import { useEffect, useMemo, useState } from 'react'
import { useMemo, useState } from 'react'

type ChartBarDisplayMode = 'grouped' | 'stacked'

Expand Down Expand Up @@ -291,16 +291,6 @@ export function useFundraisingDashboardController() {
]
)

useEffect(() => {
setChartViewOverrideRange(null)
}, [startDate, endDate, committedPreset])

useEffect(() => {
if (!zoomEnabled) {
setChartViewOverrideRange(null)
}
}, [zoomEnabled])

const chartBucketQueries = useQueries({
queries: chartBuckets.map((bucket) => ({
queryKey: [
Expand Down Expand Up @@ -340,11 +330,12 @@ export function useFundraisingDashboardController() {
})
}, [chartBuckets, chartBucketQueries])

useEffect(() => {
if (!validGranularityModes.includes(granularityMode)) {
setGranularityMode('auto')
}
}, [validGranularityModes, granularityMode])
if (
granularityMode != 'auto' &&
!validGranularityModes.includes(granularityMode)
) {
setGranularityMode('auto')
}

const selectedRangeLabel = useMemo(
() => getSelectedRangeLabel(committedPreset, startDate, endDate),
Expand Down Expand Up @@ -398,7 +389,6 @@ export function useFundraisingDashboardController() {
return
}
}

setChartViewOverrideRange(range)
}

Expand Down
17 changes: 7 additions & 10 deletions src/app/admin/panels/members/panel_views/DonorView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type { UseQueryResult } from '@tanstack/react-query'
import cx from 'classnames'
import { motion } from 'motion/react'
import Link from 'next/link'
import React, { ChangeEvent, useEffect, useMemo, useState } from 'react'
import React, { ChangeEvent, useMemo, useState } from 'react'

export interface DonorViewProps {
selectedId: number
Expand Down Expand Up @@ -144,15 +144,12 @@ export function DonorView({

const [overlayMounted, setOverlayMounted] = useState(false)
const [overlayOpen, setOverlayOpen] = useState(false)

useEffect(() => {
if (pickingDonor) {
setOverlayMounted(true)
requestAnimationFrame(() => setOverlayOpen(true))
} else if (overlayMounted) {
setOverlayOpen(false)
}
}, [pickingDonor, overlayMounted])
if (pickingDonor) {
setOverlayMounted(true)
requestAnimationFrame(() => setOverlayOpen(true))
} else if (overlayMounted) {
setOverlayOpen(false)
}

const backdropVariants = {
open: {
Expand Down
9 changes: 6 additions & 3 deletions src/app/endorsements/components/FilterButtonRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ export function FilterButtonRow({
})
})
}
if (!mobile && prev) {
// If we're transitioning from mobile to non-mobile, reset the layout
setMobileSearchWidth(null)
setSingleColumnLayout(false)
setShowSearchLabel(false)
}
return mobile
})
if (mobile) {
Expand All @@ -207,9 +213,6 @@ export function FilterButtonRow({

useLayoutEffect(() => {
if (!isMobile) {
setMobileSearchWidth(null)
setSingleColumnLayout(false)
setShowSearchLabel(false)
Comment thread
LNorman8 marked this conversation as resolved.
return
}

Expand Down
16 changes: 6 additions & 10 deletions src/app/home/MemberBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export function safeLogError(err: unknown, prefix = '') {
export function MemberBanner() {
const { inView, observe } = useInView()
const containerRef = useRef<HTMLDivElement>(null)
const [visible, setVisible] = useState<boolean>(false)
const [latchVisible, setLatchVisible] = useState<boolean>(false)
const loggedInUser = useCurrentUser()
const discordId = loggedInUser?.data?.discordUsers?.[0]?.id ?? null

Expand All @@ -184,13 +184,9 @@ export function MemberBanner() {
}
}, [observe])

useEffect(() => {
try {
if (inView) setVisible(true)
} catch (err) {
safeLogError(err, 'inView effect error:')
}
}, [inView])
if (!latchVisible && inView) {
setLatchVisible(true)
}

return (
<div className={styles.section}>
Expand All @@ -206,7 +202,7 @@ export function MemberBanner() {
<motion.div
className={styles.cardColumn}
initial={{ opacity: 0, y: 50 }}
animate={visible ? { opacity: 1, y: 0 } : {}}
animate={latchVisible ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.8, ease: 'easeOut' }}
>
<div className={styles.cardColumnInner}>
Expand All @@ -225,7 +221,7 @@ export function MemberBanner() {
</div>
</motion.div>

<MembershipBulletPoints visible={visible} />
<MembershipBulletPoints visible={latchVisible} />
</div>
</div>
</div>
Expand Down
6 changes: 2 additions & 4 deletions src/app/home/Volunteer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import styles from './volunteer.module.css'
import { motion } from 'motion/react'
import Image from 'next/image'
import { useState, useEffect, useRef } from 'react'
import { useEffect, useRef, useState } from 'react'

const actions = [
{
Expand Down Expand Up @@ -35,9 +35,7 @@ export function Volunteer() {
if (divRef.current) observe(divRef.current)
}, [observe])

useEffect(() => {
if (inView) setVisible(true)
}, [inView])
if (!visible && inView) setVisible(true)

return (
<div className={styles.container}>
Expand Down
10 changes: 6 additions & 4 deletions src/app/login/LoginCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useAuth } from '@/util/hooks'
import Image from 'next/image'
import { useSearchParams } from 'next/navigation'
import { useEffect } from 'react'

export function LoginCard() {
const { session, onLogin } = useAuth()
Expand All @@ -19,10 +20,11 @@ export function LoginCard() {
? 'An unknown error occurred. Please try again later.'
: null

if (session) {
window.location.href = redirect
return null
}
useEffect(() => {
if (session) {
window.location.href = redirect
}
}, [session, redirect])
Comment thread
LNorman8 marked this conversation as resolved.

return (
<div className="flex max-w-[30rem] flex-col items-center justify-center gap-6 rounded-md bg-black-pearl-dark p-8 text-center shadow-lg">
Expand Down
21 changes: 10 additions & 11 deletions src/app/volunteer/CollectInfoStage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useFetch, useInit } from '@/util/hooks'
import Link from 'next/link'
import phone from 'phone'
import { Country, isValidCountryPostalCode } from 'postal-code-validator'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useMemo, useState } from 'react'

export interface IOnboardingForm {
firstName: string
Expand Down Expand Up @@ -50,12 +50,19 @@ export function CollectInfoStage({
)
const [zipCodeError, setZipCodeError] = useState(false)

const parsePhone = (number: string) =>
phone(number, {
const parsePhone = (number: string) => {
const p = phone(number, {
country: 'US',
strictDetection: true,
validateMobilePrefix: true,
})
if (p.isValid)
setForm((f) => ({
...f,
phoneNumber: number.substring(2),
}))
return p
}
const parsedPhone = useMemo(() => parsePhone(phoneNumber), [phoneNumber])

const setFormattedPhoneNumber = (number: string) => {
Expand Down Expand Up @@ -99,14 +106,6 @@ export function CollectInfoStage({

useInit(() => setFormattedPhoneNumber(initialForm.phoneNumber))

useEffect(() => {
if (parsedPhone.isValid)
setForm((f) => ({
...f,
phoneNumber: parsedPhone.phoneNumber.substring(2),
}))
}, [parsedPhone])

return (
<div>
<header>
Expand Down
Loading
Loading