Skip to content

Instantly share code, notes, and snippets.

@toastdriven
Last active April 20, 2022 15:37
Show Gist options
  • Save toastdriven/98448c0a3a25825fa60e56dca43d8d76 to your computer and use it in GitHub Desktop.
Save toastdriven/98448c0a3a25825fa60e56dca43d8d76 to your computer and use it in GitHub Desktop.
import { useState, useEffect } from 'react';
import { useQuery } from 'react-query';
// Pretend this is real & extracts server-side data from a hidden element with
// `data-*` attributes or similar.
import { pageContext } from '../utils/pageTools';
// Again, pretend this is real & handles websocket comms.
import {
followUserActivity,
followTeamActivity,
unfollowUserActivity,
unfollowTeamActivity,
} from '../websockets';
/* Queries */
const commonHeaders = {
"Content-Type": "application/json",
"Accept": "application/json",
};
const _getRequest = async (url) => {
const resp = await fetch(url, {
method: "GET",
headers: commonHeaders,
});
if (!resp.ok) throw new Error(resp.statusText);
return resp.json();
};
const getUser = async (userId) => {
const url = `/api/v1/users/${userId}/`;
return await _getRequest(url);
};
const getCommits = async (teamId) => {
const url = `/api/v1/commits/${teamId}/`;
return await _getRequest(url);
};
/* Low-Level Components */
const Loading = () => {
return (
<div>
PRETEND I'M A SPINNER! WHEE!
</div>
);
};
const Gravatar = ({ email, ...props }) => {
// This is fake, but pretend it's real, for the sake of dumb low-level
// components.
const imgUrl = `https://en.gravatar.com/thumb/${email}.jpg`;
return (
<div className="rounded-m w-8 h-8">
<img src={imgUrl} alt={email} />
</div>
);
};
const Commit = ({ sha, repo, message, committer, ...props }) => {
const commitUrl = `https://github.com/${repo}/${sha}`;
const handleClick = (commitUrl) => {
// Yes, this is awful. Play along.
window.open(commitUrl, "_blank");
};
return (
<div
className="my-4 mx-4 flex"
onClick={handleClick(commitUrl)}
>
<div className="flex-auto mr-4 max-w-16">
<Gravatar email={committer} />
</div>
<div className="flex-auto">
<div className="mb-2 border-b-2 border-solid border-gray-500">
Committed by <strong>{committer}</strong>
</div>
<div className="mt-2 text-gray-200">
{message}
</div>
</div>
</div>
);
};
/* High-Level Components */
const CommitList = ({ teamId, setTeamId, ...props }) => {
// This needs to be a separate component, because we can't do a dependent
// query below.
// We don't have the team ID until the user data is done being fetched, & we
// can't put `useQuery` in a conditional because of how hooks work.
const teamCommits = useQuery(["commits", teamId], () => getCommits(teamId));
if (teamCommits.isLoading) {
return (<Loading />);
}
return (
<div>
<h3>Recent Commits by {teamCommits.data.teamName}</h3>
<div>
{/* I hate JSX & I hate how I have to do conditionals. Eff this noise. */}
{teamCommits.data.commits.length() > 0 ?
teamCommits.data.commits.map((commit, commitOffset) => {
return (
<Commit sha={commit.sha} repo={teamCommits.data.teamRepo} message={commit.message} committer={commit.email} />
);
})
: "No commits found."}
</div>
</div>
)
};
/* Page Component */
export const TeamActivityPage = (props) => {
const context = pageContext("#page-context");
const [userId, setUserId] = useState(context.userId);
const [teamId, setTeamId] = useState();
// We need the user's data to grab their `teamId` out of it.
const user = useQuery(["users", userId], () => getUser(userId));
// Ugh, the `useEffect` has to go before the conditional return.
// Because something something hook ordering.
useEffect(() => {
// This is tenuous at best, (trying to keep this simple), but having to
// kick things off when the data changes is a frequent thing I run into.
unfollowUserActivity();
followUserActivity(userId);
}, [userId]);
if (user.isLoading) {
return (<Loading />);
}
// How often does this code run? On every repaint?
setTeamId(user.data.team_id);
// We'll skip the request error cases for brevity & just do the JSX.
return (
<div>
<h2>Team Activity</h2>
<div>
<CommitList teamId={teamId} setTeamId={setTeamId} />
</div>
</div>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment