username input, buttons roundness, conditions for mocking & caching & local computation

This commit is contained in:
martin-mfg
2025-12-10 11:13:09 +01:00
parent 96db43215d
commit 0cd4347e3f
5 changed files with 92 additions and 31 deletions
+11 -4
View File
@@ -20,6 +20,9 @@ const cachedAxios = setupCache(axios, {
interpretHeader: false,
cacheTakeover: false,
methods: ['get', 'post'],
cachePredicate: {
allowUrls: ['api.github.com', HOST],
},
});
axios.get = cachedAxios.get.bind(cachedAxios);
@@ -36,17 +39,21 @@ function createMockResponse(data, config) {
});
}
// store isAuthenticated outside React context so the interceptor can access it
let isAuthenticated = null;
// store shouldMock outside React context so the interceptor can access it
let shouldMock = null;
export function setIsAuthenticated(newIsAuthenticated) {
isAuthenticated = newIsAuthenticated;
export function setShouldMock(newShouldMock) {
shouldMock = newShouldMock;
}
const defaultAdapter = getAdapter(axios.defaults.adapter);
// mock responses to "anuraghazra" requests
axios.defaults.adapter = async (config) => {
if (!shouldMock) {
return defaultAdapter(config);
}
const params = config.data ? JSON.parse(config.data) : {};
if (
+21 -22
View File
@@ -9,7 +9,7 @@ import 'react-loading-skeleton/dist/skeleton.css';
import { createMockReq, createMockRes } from '../../mock-http';
import { default as router } from '../../backend/.vercel/output/functions/api.func/router.js';
import { setIsAuthenticated } from '../../axios-override';
import { setShouldMock } from '../../axios-override';
import {
useIsAuthenticated,
useUserToken,
@@ -21,12 +21,12 @@ const SvgInline = (props) => {
const containerRef = useRef(null);
const userToken = useUserToken();
const isAuthenticated = useIsAuthenticated();
const { url } = props;
const { url, stage } = props;
// provide isAuthenticated to non-react code in axios-override.js
// provide shouldMock to non-react code in axios-override.js
useEffect(() => {
setIsAuthenticated(isAuthenticated);
}, [isAuthenticated]);
setShouldMock(stage === 0 || !isAuthenticated);
}, [isAuthenticated, props.stage]);
useEffect(() => {
const loadSvg = async () => {
@@ -42,22 +42,20 @@ const SvgInline = (props) => {
return;
}
// if (isAuthenticated) {
const req = createMockReq({
method: 'GET',
url: url,
});
const res = createMockRes();
await router(req, res);
body = res._getBody();
status = res._getStatusCode();
/*
} else {
let res = await axios.get(url);
body = res.data;
status = res.status;
}
*/
if (stage === 4 && !isAuthenticated) {
let res = await axios.get(url);
body = res.data;
status = res.status;
} else {
const req = createMockReq({
method: 'GET',
url: url,
});
const res = createMockRes();
await router(req, res);
body = res._getBody();
status = res._getStatusCode();
}
if (status >= 300) {
console.error('failed to fetch/generate SVG');
@@ -68,7 +66,7 @@ const SvgInline = (props) => {
setLoaded(true);
};
loadSvg();
}, [userToken, isAuthenticated, props.url]);
}, [userToken, isAuthenticated, props.url, props.stage]);
useEffect(() => {
if (loaded && svg && containerRef.current) {
@@ -103,6 +101,7 @@ SvgInline.propTypes = {
url: PropTypes.string.isRequired,
forceLoading: PropTypes.bool,
compact: PropTypes.bool,
stage: PropTypes.number.isRequired,
};
SvgInline.defaultProps = {
@@ -11,7 +11,7 @@ const Button = (props) => {
{...props}
className={classnames(
props.className,
'border-0 py-2 px-6 inline-flex focus:outline-none rounded-s text-lg',
'border-0 py-2 px-6 inline-flex focus:outline-none rounded-md text-lg',
)}
>
{props.children}
+5 -3
View File
@@ -44,6 +44,7 @@ const HomeScreen = ({ stage, setStage }) => {
const login = (newUserId, userKey) => dispatch(_login(newUserId, userKey));
// for stage two
const [selectedUserId, setSelectedUserId] = useState(userId);
const [repo, setRepo] = useState(DEMO_REPO);
const [gist, setGist] = useState(DEMO_GIST);
const [wakatimeUser, setWakatimeUser] = useState(DEMO_WAKATIME_USER);
@@ -104,7 +105,7 @@ const HomeScreen = ({ stage, setStage }) => {
switch (selectedCard) {
case CardTypes.STATS:
case CardTypes.TOP_LANGS:
fullSuffix += `username=${userId}`;
fullSuffix += `username=${selectedUserId}`;
break;
case CardTypes.PIN:
fullSuffix += `username=${userId}&repo=${repo}`;
@@ -374,6 +375,8 @@ const HomeScreen = ({ stage, setStage }) => {
setIncludeAllCommits={setIncludeAllCommits}
enableAnimations={enableAnimations}
setEnableAnimations={setEnableAnimations}
selectedUserId={selectedUserId}
setSelectedUserId={setSelectedUserId}
repo={repo}
setRepo={setRepo}
gist={gist}
@@ -399,9 +402,8 @@ const HomeScreen = ({ stage, setStage }) => {
filename={(() => {
switch (selectedCard) {
case CardTypes.STATS:
return `${userId}_card`;
case CardTypes.TOP_LANGS:
return `${userId}_card`;
return `${selectedUserId}_card`;
case CardTypes.PIN:
return `${repo}_card`;
case CardTypes.GIST:
@@ -8,7 +8,12 @@ import NumericSection from '../../../components/Home/NumericSection';
import StatsRankSection from '../../../components/Home/StatsRankSection';
import LanguagesLayoutSection from '../../../components/Home/LanguagesLayoutSection';
import WakatimeLayoutSection from '../../../components/Home/WakatimeLayoutSection';
import { DEMO_GIST, DEMO_REPO, DEMO_WAKATIME_USER } from '../../../constants';
import {
DEMO_GIST,
DEMO_REPO,
DEMO_USER,
DEMO_WAKATIME_USER,
} from '../../../constants';
import { useIsAuthenticated } from '../../../redux/selectors/userSelectors';
const CustomizeStage = ({
@@ -19,6 +24,8 @@ const CustomizeStage = ({
setSelectedLanguagesLayout,
selectedWakatimeLayout,
setSelectedWakatimeLayout,
selectedUserId,
setSelectedUserId,
repo,
setRepo,
gist,
@@ -93,6 +100,50 @@ const CustomizeStage = ({
setSelectedOption={setSelectedLanguagesLayout}
/>
)}
{(cardType === CardTypes.STATS || cardType === CardTypes.TOP_LANGS) && (
<TextSection
title="Username"
description={
<>
Enter a GitHub username.
<br />
{!isAuthenticated && (
<>
Please{' '}
<a
href="#"
onClick={(e) => {
e.preventDefault();
setStage(0);
}}
className="underline text-blue-900"
>
log in
</a>{' '}
to change the username.
</>
)}
</>
}
placeholder={`e.g. "${DEMO_USER}"`}
value={selectedUserId}
setValue={setSelectedUserId}
onPaste={(e) => {
e.preventDefault();
let newValue = e.clipboardData.getData('text');
// if the user pasted a full GitHub URL, extract username
if (newValue.endsWith('/')) {
newValue = newValue.slice(0, -1);
}
let parts = newValue.split('/');
if (parts.length > 1) {
newValue = parts.slice(-1).join('/');
}
setRepo(newValue);
}}
disabled={!isAuthenticated}
/>
)}
{cardType === CardTypes.PIN && (
<TextSection
title="Repository"
@@ -302,6 +353,8 @@ CustomizeStage.propTypes = {
setSelectedLanguagesLayout: PropTypes.func.isRequired,
selectedWakatimeLayout: PropTypes.object.isRequired,
setSelectedWakatimeLayout: PropTypes.func.isRequired,
selectedUserId: PropTypes.string.isRequired,
setSelectedUserId: PropTypes.func.isRequired,
repo: PropTypes.string.isRequired,
setRepo: PropTypes.func.isRequired,
gist: PropTypes.string.isRequired,