Last active
April 20, 2022 15:37
-
-
Save toastdriven/98448c0a3a25825fa60e56dca43d8d76 to your computer and use it in GitHub Desktop.
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
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