• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iamogbz / letters-from-the-abyss / #72

03 Nov 2024 04:07PM UTC coverage: 61.579%. Remained the same
#72

push

iamogbz
fix: start with poem halfway up the screen

10 of 23 branches covered (43.48%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

107 of 167 relevant lines covered (64.07%)

6.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.5
/src/components/PoemCollection.tsx
1
import React from "react";
2
// import ReactList from "react-list";
3
import stories from "../utils/stories.json";
4
import { PoemDetails, PoemImage } from "./PoemCard";
5
import "./PoemCollection.css";
6
import { useOnNavigation } from "./hooks/useOnNavigation";
7
import { isPageLocallyLiked, logPoemLike } from "../utils/hitCounter";
8
import { sharePoem } from "../utils/share";
9
import { useValue } from "./hooks/useValue";
10

11
function Button(props: React.InputHTMLAttributes<HTMLInputElement>) {
12
  return <input {...props} type="button" />;
8✔
13
}
14

15
function PoemCollection() {
16
  const pageHash = useValue(() => document.location.hash);
2✔
17

18
  const poemEntries = React.useMemo(() => {
2✔
19
    const [first, ...rest] = Object.entries(stories.data.published).sort(
2✔
20
      (a, b) => {
21
        // sort poems by date
22
        return a[1].localeCompare(b[1]);
272✔
23
      }
24
    );
25
    const [last, ...poems] = rest.reverse();
2✔
26
    // randomise the poems but keep the first and last in place
27
    return [first, ...poems.sort(() => Math.random() - 0.5), last];
244✔
28
  }, []);
29

30
  const [isCurrentPoemLiked, setIsCurrentPoemLiked] = React.useState(false);
2✔
31
  const likePoem = React.useCallback(async () => {
2✔
32
    await logPoemLike();
×
33
    setIsCurrentPoemLiked(isPageLocallyLiked());
×
34
    alert("Awesome, thank you for your feedback!");
×
35
  }, []);
36
  useOnNavigation({
2✔
37
    callback: () => setIsCurrentPoemLiked(isPageLocallyLiked()),
×
38
  });
39

40
  const pages = React.useMemo(() => {
2✔
41
    return Array(poemEntries.length)
2✔
42
      .fill(null)
43
      .map((_, i) => {
44
        const [title, date] = poemEntries[i];
70✔
45
        const entryProps = { date, key: `${title}-${i}`, title };
70✔
46
        return <PoemDetails open={true} {...entryProps} />;
70✔
47
      });
48
  }, [poemEntries]);
49

50
  const openPageNumber = React.useMemo(
2✔
51
    () =>
52
      Math.max(
2✔
53
        0,
54
        pages.findIndex((el) => pageHash.endsWith(el.props.title))
70✔
55
      ),
56
    [pageHash, pages]
57
  );
58

59
  const isOnFirstPage = openPageNumber === 0;
2✔
60
  const isOnLastPage = openPageNumber === pages.length - 1;
2✔
61

62
  const goToPage = React.useCallback(
2✔
63
    (pageNum: number) => {
64
      document.location.hash = poemEntries[pageNum][0];
×
65
    },
66
    [poemEntries]
67
  );
68

69
  const goToNextPage = React.useCallback(() => {
2✔
70
    goToPage(Math.min(openPageNumber + 1, poemEntries.length - 1));
×
71
  }, [goToPage, openPageNumber, poemEntries.length]);
72
  const goToPrevPage = React.useCallback(() => {
2✔
73
    goToPage(Math.max(openPageNumber - 1, 0));
×
74
  }, [goToPage, openPageNumber]);
75

76
  const [title, date] = poemEntries[openPageNumber];
2✔
77
  const entryProps = { date, title };
2✔
78

79
  React.useEffect(() => {
2✔
NEW
80
    const poemTitleTopPx = window.screen.height / 2;
×
81
    window.scrollTo({ top: poemTitleTopPx, behavior: "smooth" });
×
82
  }, [title]);
83

84
  return (
2✔
85
    <>
86
      <Button
87
        id="prev-btn"
88
        disabled={isOnFirstPage}
89
        value="Back ⬅️"
90
        onClick={goToPrevPage}
91
      />
92
      <Button
93
        id="next-btn"
94
        disabled={isOnLastPage}
95
        value="➡️ Next"
96
        onClick={goToNextPage}
97
      />
98
      <Button
99
        id="like-btn"
100
        value={isCurrentPoemLiked ? "Liked ❤️" : "Like ❤️"}
2!
101
        title="Like"
102
        onClick={likePoem}
103
        disabled={isCurrentPoemLiked}
104
      ></Button>
105
      <Button
106
        id="share-btn"
107
        value="🔗 Link"
108
        title="Share"
109
        onClick={sharePoem}
110
      ></Button>
111
      <PoemImage {...entryProps} />
112
      <PoemDetails {...entryProps} />
113
    </>
114
  );
115
}
116

117
PoemCollection.wrapperStyles = {
2✔
118
  // display: "flex",
119
  // flexDirection: "column",
120
  // alignItems: "center",
121
  // justifyContent: "center",
122
  get padding() {
123
    return this.gap;
×
124
  },
125
  // position: "relative",
126
  zIndex: 1,
127
} as React.CSSProperties;
128

129
export default PoemCollection;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc