Skip to content

Commit ac28ef2

Browse files
committed
typescript changelog feature
1 parent bc3a28d commit ac28ef2

12 files changed

Lines changed: 156 additions & 137 deletions

File tree

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"styled-components": "2",
3434
"timeago.js": "^4.0.2",
3535
"type-fest": "^1.2.0",
36-
"web-vitals": "^0.2.4"
36+
"web-vitals": "^0.2.4",
37+
"zustand": "^4.1.3"
3738
},
3839
"proxy": "https://api.hackertab.dev/",
3940
"scripts": {
@@ -63,12 +64,10 @@
6364
},
6465
"devDependencies": {
6566
"@types/chrome": "^0.0.198",
67+
"@types/jest": "^29.1.2",
6668
"@types/node": "^18.11.0",
6769
"@types/react": "^18.0.21",
6870
"@types/react-dom": "^18.0.6",
69-
"@types/jest": "^29.1.2",
70-
"prettier": "^2.7.1",
71-
"typescript": "^4.8.4",
7271
"@typescript-eslint/eslint-plugin": "^5.40.1",
7372
"@typescript-eslint/parser": "^5.40.1",
7473
"eslint-config-airbnb": "19.0.4",
@@ -80,6 +79,8 @@
8079
"eslint-plugin-jsx-a11y": "^6.5.1",
8180
"eslint-plugin-prettier": "^4.2.1",
8281
"eslint-plugin-react": "^7.28.0",
83-
"eslint-plugin-react-hooks": "^4.3.0"
82+
"eslint-plugin-react-hooks": "^4.3.0",
83+
"prettier": "^2.7.1",
84+
"typescript": "^4.8.4"
8485
}
8586
}

src/components/Changelog.js

Lines changed: 0 additions & 121 deletions
This file was deleted.

src/components/Header.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import SettingsModal from '../settings/SettingsModal'
99
import { BsMoon } from 'react-icons/bs'
1010
import { IoMdSunny } from 'react-icons/io'
1111
import { trackSearchEngineUse } from 'src/lib/analytics'
12-
import Changelog from './Changelog'
12+
import {Changelog} from 'src/features/changelog'
1313
import { GoSearch } from 'react-icons/go'
1414

1515
function SearchBar({ state }) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useQuery } from '@tanstack/react-query';
2+
import { ExtractFnReturnType, QueryConfig } from 'src/lib/react-query';
3+
import { Version } from "../types";
4+
import { axios } from 'src/lib/axios';
5+
6+
const getAd = async (): Promise<Version[]> => {
7+
8+
return axios.get<Version[]>('https://api.github.com/repos/medyo/hackertab.dev/releases')
9+
.then(response => {
10+
const versions = response.data as unknown as Version[];
11+
console.log("response.data", versions)
12+
return versions
13+
})
14+
}
15+
16+
type QueryFnType = typeof getAd;
17+
18+
type UseGetAdOptions = {
19+
config?: QueryConfig<QueryFnType>;
20+
};
21+
export const useGetVersions = ({ config }: UseGetAdOptions = {}) => {
22+
return useQuery<ExtractFnReturnType<QueryFnType>>({
23+
...config,
24+
queryKey: ['versions'],
25+
queryFn: () => getAd(),
26+
});
27+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React, { useEffect, useState } from 'react'
2+
import ReactTooltip from 'react-tooltip'
3+
import { HiBell } from 'react-icons/hi'
4+
import ReactMarkdown from 'react-markdown'
5+
import { format } from 'timeago.js'
6+
import BeatLoader from 'react-spinners/BeatLoader'
7+
import {useGetVersions} from "../api/getVersions";
8+
import {useChangelogStore} from "../stores/changelog";
9+
import {getAppVersion} from "src/utils/Os";
10+
11+
export const Changelog = () => {
12+
const tooltipId = 'tl-1'
13+
const [tooltipOpen, setTooltipShown] = useState(false);
14+
const {isLoading, isError, data: versions} = useGetVersions({
15+
config: {
16+
enabled: tooltipOpen
17+
}
18+
});
19+
20+
const {lastReadVersion, setVersionAsRead} = useChangelogStore();
21+
22+
const isChangelogRead = (): boolean => {
23+
return lastReadVersion === getAppVersion();
24+
}
25+
26+
useEffect(() => {
27+
if (tooltipOpen) {
28+
setVersionAsRead(getAppVersion())
29+
}
30+
}, [tooltipOpen, setVersionAsRead])
31+
32+
return (
33+
<>
34+
<ReactTooltip
35+
id={tooltipId}
36+
event="click"
37+
scrollHide={false}
38+
afterShow={() => {setTooltipShown(true)}}
39+
place="bottom"
40+
className="changelogTooltip scrollable"
41+
globalEventOff="click">
42+
{isLoading ? (
43+
<div className="tooltipLoading">
44+
<BeatLoader color={'#A9B2BD'} loading={isLoading} size={15} />
45+
</div>
46+
) : isError || !versions.length ? (
47+
<p className="tooltipErrorMsg">Failed to load the changelog</p>
48+
) : (
49+
versions.map((item) => {
50+
return (
51+
<div key={item.name}>
52+
<div className="tooltipHeader">
53+
<a className="tooltipVersion" onClick={() => window.open(item.html_url, '_blank')}>
54+
{item.name}
55+
</a>
56+
<span className="tooltipDate">{format(new Date(item.published_at))}</span>
57+
</div>
58+
<div className="tooltipContent">
59+
<ReactMarkdown children={item.body} />
60+
</div>
61+
</div>
62+
)
63+
})
64+
)}
65+
</ReactTooltip>
66+
<span
67+
data-tip
68+
data-for={tooltipId}
69+
className={'changelogButton' + (!isChangelogRead() ? ' active' : '')}>
70+
<HiBell style={{ width: 14 }} />
71+
</span>
72+
</>
73+
)
74+
}

src/features/changelog/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./types"
2+
export * from "./components/Changelog"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import create from 'zustand';
2+
import { persist } from 'zustand/middleware'
3+
4+
type ChangelogVersionStore = {
5+
lastReadVersion: string | undefined | null;
6+
setVersionAsRead: (versionName: string | undefined | null) => void;
7+
};
8+
9+
export const useChangelogStore = create(persist<ChangelogVersionStore>((set) => ({
10+
lastReadVersion: undefined,
11+
setVersionAsRead: (versionName: string | undefined | null) =>
12+
set(() => ({
13+
lastReadVersion: versionName,
14+
}))
15+
}),{
16+
name: 'changelog_storage',
17+
}));
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type Version = {
2+
name: string;
3+
published_at: string;
4+
body: string;
5+
html_url: string;
6+
}

src/lib/analytics.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import AppStorage from '../services/localStorage';
22
import { init, track, identify, Identify } from '@amplitude/analytics-browser'
33
import { isDevelopment } from 'src/utils/Environment';
44
import { ANALYTICS_SDK_KEY, ANALYTICS_ENDPOINT, LS_ANALYTICS_ID_KEY } from 'src/Constants'
5+
import {getAppVersion} from "src/utils/Os";
56

67
enum Objects {
78
PAGE = 'Page',
@@ -305,14 +306,7 @@ const getRandomUserId = () => {
305306
return userId
306307
}
307308

308-
const getAppVersion = (): string | undefined => {
309-
try {
310-
var manifestData = chrome.runtime.getManifest()
311-
return manifestData.version
312-
} catch (e) {
313-
return undefined
314-
}
315-
}
309+
316310
const getScreenResolution = (): string => {
317311
const realWidth = window.screen.width
318312
const realHeight = window.screen.height
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import React from 'react'
22

33
const PreferencesContext = React.createContext({
44
userSelectedTags: [],
5-
dispatcher: null
5+
dispatcher: null,
6+
changelogMeta: {
7+
shown: false,
8+
version: "",
9+
}
610
});
711

812

0 commit comments

Comments
 (0)