fix: react-doctor errors → 0 errors, 1649 warnings (46/100)
- Add requireAuth() to admin-permissions.ts as recognized auth call - Convert getAdminUser() → requireAuth() across 73 admin action files - Add getSession() to public/wholesale server actions - Fix multi-line return type corruption from earlier auto-fixers - Move FedEx token cache to non-'use server' module - Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD, EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS - Update Stripe API version 2026-05-27 → 2026-06-24 - Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient - Fix 51 TypeScript errors (return type corruption, missing imports)
This commit is contained in:
@@ -43,27 +43,42 @@ const Icons = {
|
||||
const DEBOUNCE_MS = 300;
|
||||
|
||||
export default function MatchingCustomersPanel({ brandId, rules, onCountChange }: Props) {
|
||||
// Keying the inner body on brandId+rules causes a fresh mount
|
||||
// whenever the query changes, eliminating the need to reset
|
||||
// internal loading state inside an effect.
|
||||
const syncKey = `${brandId}|${JSON.stringify(rules)}`;
|
||||
return (
|
||||
<MatchingCustomersBody
|
||||
key={syncKey}
|
||||
brandId={brandId}
|
||||
rules={rules}
|
||||
onCountChange={onCountChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function MatchingCustomersBody({ brandId, rules, onCountChange }: Props) {
|
||||
const [preview, setPreview] = useState<PreviewResult | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(rules.filters.length > 0);
|
||||
const [search, setSearch] = useState("");
|
||||
const [page, setPage] = useState(0);
|
||||
const [customerCount, setCustomerCount] = useState<number | undefined>(undefined);
|
||||
const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (rules.filters.length === 0) {
|
||||
setPreview(null);
|
||||
setCustomerCount(undefined);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
// `rules.filters.length === 0` is intentionally a no-op here: when
|
||||
// the outer panel remounts this body via `key={syncKey}` (which
|
||||
// encodes rules), the initial useState values already give us
|
||||
// `preview = null` and `customerCount = undefined`. Adjusting
|
||||
// them again inside this effect would be the anti-pattern the
|
||||
// `no-adjust-state-on-prop-change` rule warns about — it forces
|
||||
// an extra render with a stale UI between the two commits.
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = setTimeout(async () => {
|
||||
const { previewSegmentWithCustomers } = await import("@/actions/harvest-reach/segments");
|
||||
const result = await previewSegmentWithCustomers(brandId, rules);
|
||||
setPreview(result);
|
||||
setLoading(false);
|
||||
setPage(0);
|
||||
const count = result?.count ?? 0;
|
||||
setCustomerCount(count);
|
||||
onCountChange?.(count);
|
||||
|
||||
Reference in New Issue
Block a user