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

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

01 May 2024 09:10AM UTC coverage: 61.17% (-3.7%) from 64.851%
#68

push

web-flow
fix: update website design (#8)

* wip: replace actual api call with localhost in dev mode

* wip: update designs step 1

* wip: update designs step 2

* wip: update designs step 3

* test: specify test location host

* chore: remove obsolete console logs

* wip: add welcome and credits notes

* feat: add share and like alerts

* fix: make actions more visible on mobile

* chore: make poem more visible on mobile

* wip: position buttons better

* wip: scroll poem into page when first shown

* wip: update button shadows

10 of 23 branches covered (43.48%)

Branch coverage included in aggregate %.

31 of 49 new or added lines in 6 files covered. (63.27%)

3 existing lines in 1 file now uncovered.

105 of 165 relevant lines covered (63.64%)

4.64 hits per line

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

71.05
/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
    // sort poems by date
20
    return Object.entries(stories.data.published).sort((a, b) => {
2✔
21
      return a[1].localeCompare(b[1]);
218✔
22
    });
23
  }, []);
24

25
  const [isCurrentPoemLiked, setIsCurrentPoemLiked] = React.useState(false);
2✔
26
  const likePoem = React.useCallback(async () => {
2✔
NEW
27
    await logPoemLike();
×
NEW
28
    setIsCurrentPoemLiked(isPageLocallyLiked());
×
NEW
29
    alert('Awesome, thank you for your feedback!');
×
30
  }, []);
31
  useOnNavigation({
2✔
NEW
32
    callback: () => setIsCurrentPoemLiked(isPageLocallyLiked()),
×
33
  });
34

35
  const pages = React.useMemo(() => {
2✔
36
    return Array(poemEntries.length)
2✔
37
      .fill(null)
38
      .map((_, i) => {
39
        const [title, date] = poemEntries[i];
60✔
40
        const entryProps = { date, key: `${title}-${i}`, title };
60✔
41
        return <PoemDetails open={true} {...entryProps} />;
60✔
42
      });
43
  }, [poemEntries]);
44

45
  const openPageNumber = React.useMemo(
2✔
46
    () =>
47
      Math.max(
2✔
48
        0,
49
        pages.findIndex((el) => pageHash.endsWith(el.props.title))
60✔
50
      ),
51
    [pageHash, pages]
52
  );
53

54
  const isOnFirstPage = openPageNumber === 0;
2✔
55
  const isOnLastPage = openPageNumber === pages.length - 1;
2✔
56

57
  const goToPage = React.useCallback(
2✔
58
    (pageNum: number) => {
NEW
59
      document.location.hash = poemEntries[pageNum][0];
×
60
    },
61
    [poemEntries]
62
  );
63

64
  const goToNextPage = React.useCallback(() => {
2✔
NEW
65
    goToPage(Math.min(openPageNumber + 1, poemEntries.length - 1));
×
66
  }, [goToPage, openPageNumber, poemEntries.length]);
67
  const goToPrevPage = React.useCallback(() => {
2✔
NEW
68
    goToPage(Math.max(openPageNumber - 1, 0));
×
69
  }, [goToPage, openPageNumber]);
70

71
  const [title, date] = poemEntries[openPageNumber];
2✔
72
  const entryProps = { date, title };
2✔
73

74
  React.useEffect(() => {
2✔
NEW
75
    const poemTitleTopPx = 160;
×
NEW
76
    window.scrollTo({ top: poemTitleTopPx, behavior: "smooth" });
×
77
  }, [title]);
78

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

112
PoemCollection.wrapperStyles = {
2✔
113
  // display: "flex",
114
  // flexDirection: "column",
115
  // alignItems: "center",
116
  // justifyContent: "center",
117
  get padding() {
NEW
118
    return this.gap;
×
119
  },
120
  // position: "relative",
121
  zIndex: 1,
122
} as React.CSSProperties;
123

124
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