-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor: Componentify participant condition, loader container, and c…
…leanup several imports (#917) * fix: Pass participant id to get experiment collection * fix(lint): Fix formatting in App.jsx * test: Update ExperimentCollectionDashboard.test.tsx with new tests and fix linting issues * refactor: Migrate Zustand store to Typescript and add optional Sentry error capture * type: Add Participant interface * revert: Use existing fetch participant functionality and make sure participant is loaded before fetching the experiment collection * refactor: Convert App.jsx & config.js to .tsx and .ts files * refactor: Update Participant "current" view to include participant_id_url field * refactor: Use participantIdUrl instead of participantId to link / redirect to experiments with pre-existing participant_id(_url) * refactor: Add LoaderContainer and ConditionalRender components * refactor: Update CongoSameDiff to get participant's group variant based on participant's id or random number * fix: Handle missing participant / participant id in experiment collection * test: Test link to experiment with participant id url param * refactor: Remove unused import in ExperimentCollection.tsx * fix: Fix linting warnings
- Loading branch information
1 parent
cd6cf9f
commit c5422eb
Showing
32 changed files
with
322 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { useEffect } from "react"; | ||
import { | ||
BrowserRouter as Router, | ||
Switch, | ||
Route, | ||
Redirect | ||
} from "react-router-dom"; | ||
import axios from "axios"; | ||
|
||
import { API_BASE_URL, EXPERIMENT_SLUG, URLS } from "@/config"; | ||
import { URLS as API_URLS } from "../../API"; | ||
import useBoundStore from "../../util/stores"; | ||
import Experiment from "../Experiment/Experiment"; | ||
import ExperimentCollection from "../ExperimentCollection/ExperimentCollection"; | ||
import LoaderContainer from "../LoaderContainer/LoaderContainer"; | ||
import ConditionalRender from "../ConditionalRender/ConditionalRender"; | ||
import Profile from "../Profile/Profile"; | ||
import Reload from "../Reload/Reload"; | ||
import StoreProfile from "../StoreProfile/StoreProfile"; | ||
import useDisableRightClickOnTouchDevices from "../../hooks/useDisableRightClickOnTouchDevices"; | ||
|
||
|
||
// App is the root component of our application | ||
const App = () => { | ||
const error = useBoundStore(state => state.error); | ||
const setError = useBoundStore(state => state.setError); | ||
const participant = useBoundStore((state) => state.participant); | ||
const setParticipant = useBoundStore((state) => state.setParticipant); | ||
const setParticipantLoading = useBoundStore((state) => state.setParticipantLoading); | ||
const queryParams = window.location.search; | ||
|
||
useDisableRightClickOnTouchDevices(); | ||
|
||
useEffect(() => { | ||
const urlParams = new URLSearchParams(queryParams); | ||
const participantId = urlParams.get('participant_id'); | ||
let participantQueryParams = ''; | ||
if (participantId) { | ||
participantQueryParams = `?participant_id=${participantId}`; | ||
} | ||
try { | ||
axios.get(API_BASE_URL + API_URLS.participant.current + participantQueryParams).then(response => { | ||
setParticipant(response.data); | ||
}); | ||
} catch (err) { | ||
console.error(err); | ||
setError('Could not load participant', err); | ||
} finally { | ||
setParticipantLoading(false); | ||
} | ||
}, [setError, queryParams, setParticipant]) | ||
|
||
if (error) { | ||
return <p className="aha__error">Error: {error}</p>; | ||
} | ||
|
||
return ( | ||
<Router className="aha__app"> | ||
<ConditionalRender condition={!!participant} fallback={<LoaderContainer />}> | ||
<Switch> | ||
{/* Request reload for given participant */} | ||
<Route path={URLS.reloadParticipant}> | ||
<Reload /> | ||
</Route> | ||
|
||
{/* Default experiment */} | ||
<Route path="/" exact> | ||
<Redirect | ||
to={URLS.experiment.replace(":slug", EXPERIMENT_SLUG)} | ||
/> | ||
</Route> | ||
|
||
{/* Profile */} | ||
<Route path={URLS.profile} exact> | ||
<Profile slug={EXPERIMENT_SLUG} /> | ||
</Route> | ||
|
||
{/* Experiment Collection */} | ||
<Route path={URLS.experimentCollection} component={ExperimentCollection} /> | ||
|
||
{/* Experiment */} | ||
<Route path={URLS.experiment} component={Experiment} /> | ||
|
||
<Route path={URLS.session} /> | ||
|
||
{/* Store profile */} | ||
<Route | ||
path={URLS.storeProfile} | ||
exact | ||
component={StoreProfile} | ||
/> | ||
</Switch> | ||
</ConditionalRender> | ||
|
||
|
||
</Router > | ||
); | ||
}; | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
frontend/src/components/ConditionalRender/ConditionalRender.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import ConditionalRender from "./ConditionalRender"; | ||
import { render, screen } from '@testing-library/react'; | ||
import { it, expect, describe } from "vitest"; | ||
|
||
describe("ConditionalRender Component", () => { | ||
it("should render children when condition is true", () => { | ||
render( | ||
<ConditionalRender condition={true} fallback={<div>fallback</div>}> | ||
<div>children</div> | ||
</ConditionalRender> | ||
); | ||
|
||
expect(document.body.contains(screen.getByText("children"))).toBe(true); | ||
expect(document.body.contains(screen.queryByText("fallback"))).toBe(false); | ||
}); | ||
|
||
it("should render fallback when condition is false", () => { | ||
render( | ||
<ConditionalRender condition={false} fallback={<div>fallback</div>}> | ||
<div>children</div> | ||
</ConditionalRender> | ||
); | ||
|
||
expect(document.body.contains(screen.getByText("fallback"))).toBe(true); | ||
expect(document.body.contains(screen.queryByText("children"))).toBe(false); | ||
}); | ||
|
||
it("should render nothing when fallback is not provided and condition is false", () => { | ||
const { container } = render( | ||
<ConditionalRender condition={false}> | ||
<div>children</div> | ||
</ConditionalRender> | ||
); | ||
|
||
expect(container.firstChild).toBeNull(); | ||
}); | ||
}); |
17 changes: 17 additions & 0 deletions
17
frontend/src/components/ConditionalRender/ConditionalRender.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React from 'react'; | ||
|
||
interface ConditionalRenderProps { | ||
condition: boolean; | ||
children?: React.ReactNode; | ||
fallback?: React.ReactNode; | ||
} | ||
|
||
const ConditionalRender = ({ condition, children, fallback }: ConditionalRenderProps) => { | ||
if (condition) { | ||
return children; | ||
} | ||
|
||
return fallback || null; | ||
}; | ||
|
||
export default ConditionalRender; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.