fix(lint): clear lib/config baseline and make CI lint blocking. (#63)
Lazy-init theme from localStorage, hoist checkAuth with useCallback, named config exports for PostCSS/Tailwind, and remove the non-blocking || true wrapper from ci.yml (requires #61 + #62 merged first). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c32bbd19b6
commit
81bed51369
5 changed files with 64 additions and 59 deletions
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
|
@ -36,19 +36,7 @@ jobs:
|
|||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: npm
|
||||
- run: npm ci
|
||||
# TODO(fix-lint-baseline): drop the `|| true` wrapper once .convoys/fix-lint-baseline
|
||||
# lands. The codebase has ~100 pre-existing ESLint errors (conditional React
|
||||
# hooks, unescaped entities, etc.). For now lint runs and posts output as a
|
||||
# warning annotation so the PR check stays green while the debt is visible.
|
||||
- name: Lint (non-blocking until fix-lint-baseline)
|
||||
run: |
|
||||
set +e
|
||||
npm run lint --if-present
|
||||
status=$?
|
||||
if [ "$status" -ne 0 ]; then
|
||||
echo "::warning title=Lint errors (non-blocking)::ESLint reported errors above. Tracked in .convoys/ship-readiness.md as P1 #11.5 (fix-lint-baseline). Remove the wrapper in .github/workflows/ci.yml after baseline is fixed."
|
||||
fi
|
||||
exit 0
|
||||
- run: npm run lint --if-present
|
||||
|
||||
schema-map-fresh:
|
||||
name: Schema map up to date
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@ import { createContext, useContext, useEffect, useState } from 'react';
|
|||
|
||||
const ThemeContext = createContext();
|
||||
|
||||
function readThemeFromStorage() {
|
||||
if (typeof window === 'undefined') return 'light';
|
||||
return localStorage.getItem('theme') || 'light';
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children }) {
|
||||
const [theme, setTheme] = useState('light');
|
||||
const [theme, setTheme] = useState(readThemeFromStorage);
|
||||
|
||||
useEffect(() => {
|
||||
// Check for saved theme preference or default to light
|
||||
const savedTheme = localStorage.getItem('theme') || 'light';
|
||||
setTheme(savedTheme);
|
||||
document.documentElement.setAttribute('data-theme', savedTheme);
|
||||
}, []);
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
}, [theme]);
|
||||
|
||||
const toggleTheme = () => {
|
||||
const newTheme = theme === 'light' ? 'dark' : 'light';
|
||||
|
|
|
|||
|
|
@ -1,45 +1,56 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
|
||||
async function verifyAuthFromStorage() {
|
||||
const token = localStorage.getItem('auth_token');
|
||||
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/auth/verify', { headers });
|
||||
if (response.ok) {
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
if (token) {
|
||||
localStorage.removeItem('auth_token');
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Auth check failed:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function useAuth() {
|
||||
const [user, setUser] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
checkAuth();
|
||||
let active = true;
|
||||
|
||||
void (async () => {
|
||||
const verifiedUser = await verifyAuthFromStorage();
|
||||
if (!active) return;
|
||||
setUser(verifiedUser);
|
||||
setLoading(false);
|
||||
})();
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const checkAuth = async () => {
|
||||
try {
|
||||
// Get token from localStorage
|
||||
const token = localStorage.getItem('auth_token');
|
||||
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
// Add authorization header if token exists
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const response = await fetch('/api/auth/verify', { headers });
|
||||
if (response.ok) {
|
||||
const userData = await response.json();
|
||||
setUser(userData);
|
||||
} else {
|
||||
setUser(null);
|
||||
// Clear invalid token
|
||||
if (token) {
|
||||
localStorage.removeItem('auth_token');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Auth check failed:', error);
|
||||
setUser(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
const refreshAuth = useCallback(async () => {
|
||||
const verifiedUser = await verifyAuthFromStorage();
|
||||
setUser(verifiedUser);
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem('auth_token');
|
||||
|
|
@ -50,6 +61,6 @@ export function useAuth() {
|
|||
user,
|
||||
loading,
|
||||
logout,
|
||||
refreshAuth: checkAuth
|
||||
refreshAuth,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
export default {
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
const config = {
|
||||
content: [
|
||||
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
|
|
@ -29,4 +29,6 @@ export default {
|
|||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
Loading…
Reference in a new issue