Skip to content

Commit

Permalink
Merge pull request #6 from mornir/dev
Browse files Browse the repository at this point in the history
Refactor and more consistency between last visit an streak
  • Loading branch information
mornir authored Oct 20, 2020
2 parents cf78335 + c42572b commit 43ed81c
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 73 deletions.
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
# [WIP] Track it!
# 🕓 Track it!

> Web extension to track time wasted on addictive websites
Are there websites that you wish you would visit less often? The web counts numerous addictive, unproductive, distractive websites. This web extension shows you the last time you visited such websites and encourages you to keep off of them.

## ✨ FEATURES

✔ Choose the websites you want to track
✔ Show the collective last visit time
✔ Show the longest streak to keep you motivated
✔ Minimalist UI
✔ Privacy-focused
✔ Open-source
✔ Open-source

## 🤫 PRIVACY

This extension only reads your local history and doesn't share it. If you enabled sync for extension, the list of websites you track will be synchronized with Google account. If you disabled sync, it will only be stored locally.

## Calculation of the longest streak

The duration of longest streak is calculated between visits to exact URLs. For example, if you add "https://www.youtube.com", but always access YouTube through "https://www.youtube.com/feed/subscriptions" (e.g. via a bookmark), the later URL won't be taken into account.
The longest streak is only recorded over the last three months, because Chrome doesn't keep browser history records that are older than three months.
In my opinion, this is not an issue, because if you can refrain from visiting an addictive website for more than three months, you already succeeded.

In Chrome, the longest streak is only recorded over the last three months, because Chrome doesn't keep browser history records that are older than three months.
In my opinion, this is not an issue, because if you can refrain from visiting an addictive website for more than three months, you already succeeded. 😉

# Credits

- Cover Photo by [Aron Visuals](https://unsplash.com/@aronvisuals?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/time?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText")
- Clock icon by [bqlqn](https://www.flaticon.com/authors/bqlqn) on [flaticon](https://www.flaticon.com/)
- [vue-cli-plugin-browser-extension](https://github.com/adambullmer/vue-cli-plugin-browser-extension) by [Adam Bullmer](https://github.com/adambullmer)

# Local development

Expand All @@ -46,7 +55,3 @@ yarn build
```
yarn lint
```

### Customize configuration

See [Configuration Reference](https://cli.vuejs.org/config/).
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "track-it",
"version": "0.1.0",
"version": "0.2.0",
"description": "Web extension to track time wasted on addictive websites",
"private": true,
"scripts": {
Expand Down
Binary file removed public/favicon.ico
Binary file not shown.
28 changes: 19 additions & 9 deletions src/options/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@
</li>
</ul>
<div v-if="error">
<p>Yikes! An error occured:</p>
<pre>{{ error }}</pre>
<p class="mt-4 text-lg">Yikes! An error occured:</p>
<pre class="break-words">{{ error }}</pre>
<p>
You can report the error here:
<a href="https://github.com/mornir/track-it/issues/new"
>https://github.com/mornir/track-it/issues/new</a
>
<a
href="https://github.com/mornir/track-it/issues/new"
class="underline"
>Report the error
</a>
</p>
</div>
</section>
Expand Down Expand Up @@ -115,24 +116,25 @@
</template>

<script>
import { getLongestStreak } from '@/utils/getHistoryFunctions.js'
import { formatDistance, format } from 'date-fns'
import mixin from '@/utils/mixin.js'
import DeleteIcon from '@/assets/svg/delete.svg'
import InfoIcon from '@/assets/svg/info.svg'
export default {
mixins: [mixin],
name: 'Options',
mixins: [mixin],
components: {
DeleteIcon,
InfoIcon,
},
data() {
return {
url: '',
error: null,
urls: [],
error: null,
longestStreak: '',
streakFromDate: '',
start: {
Expand All @@ -151,7 +153,15 @@ export default {
try {
this.urls = await this.getURLListfromStorage()
const streak = await this.getLongestStreak(this.urls)
const urlsPromises = this.urls.map(url =>
browser.history.getVisits({
url,
})
)
const results = await Promise.all(urlsPromises)
const streak = getLongestStreak(results)
if (!streak) {
this.longestStreak = ''
Expand Down
74 changes: 46 additions & 28 deletions src/popup/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,93 @@
<div
class="px-4 pt-4 pb-4 text-xl text-gray-800 whitespace-no-wrap bg-gray-200"
>
<button @click="openOptionsPage" class="block mb-2 ml-auto">
<button
@click="openOptionsPage"
class="block mb-2 ml-auto"
v-if="!isListEmpty"
>
<SettingsIcon class="w-6 h-6" />
</button>
<p class="mb-6 font-light">
Last visit
<b class="block font-black font-blackish">{{ abstinenceDuration }}</b>
</p>
<p class="font-light" v-if="longestStreak">
Longest streak
<b class="block font-black font-blackish">{{ longestStreak }}</b>
</p>
<div v-if="!isListEmpty">
<p class="mb-6 font-light">
Last visit
<b class="block font-black font-blackish">{{ abstinenceDuration }}</b>
</p>
<p class="font-light" v-if="longestStreak">
Longest streak
<b class="block font-black font-blackish">{{ longestStreak }}</b>
</p>
</div>
<div v-else>
<button
@click="openOptionsPage"
class="px-4 py-1 text-lg text-white bg-blackish hover:bg-gray-700 focus:hover:bg-gray-700"
>
Start by adding websites to track
</button>
</div>
</div>
</template>

<script>
import { formatDistance } from 'date-fns'
import { getLatestVisitedSite } from '@/utils/getHistoryFunctions.js'
import {
getLatestVisitTime,
getLongestStreak,
} from '@/utils/getHistoryFunctions.js'
import SettingsIcon from '@/assets/svg/settings.svg'
import mixin from '@/utils/mixin.js'
export default {
name: 'Popup',
mixins: [mixin],
components: {
SettingsIcon,
},
name: 'Popup',
data() {
return {
latestVisitSites: [],
latestVisitSite: {},
latestVisitDate: null,
abstinenceDuration: '',
urls: [],
longestStreak: '',
streakFromDate: '',
}
},
async mounted() {
this.urls = await this.getURLListfromStorage()
if (this.urls.length === 0) {
this.abstinenceDuration = 'No URLs'
this.abstinenceDuration = ''
return
}
const urlsPromises = this.urls.map(url =>
browser.history.search({
text: url,
maxResults: 1,
startTime: 0,
browser.history.getVisits({
url,
})
)
try {
const results = await Promise.all(urlsPromises)
/** Last Visit **/
this.latestVisitSite = getLatestVisitedSite(results)
const results = await Promise.all(urlsPromises)
const latestVisitTime = getLatestVisitTime(results)
if (!this.latestVisitSite) {
if (!latestVisitTime) {
this.abstinenceDuration = 'History is empty'
return
}
this.latestVisitDate = new Date(this.latestVisitSite.lastVisitTime)
this.abstinenceDuration = formatDistance(this.latestVisitDate, new Date())
this.abstinenceDuration = formatDistance(
new Date(latestVisitTime),
new Date(),
{ addSuffix: true }
)
/** Streak **/
/** Longest Streak **/
const streak = await this.getLongestStreak(this.urls)
const streak = getLongestStreak(results)
if (!streak) {
this.longestStreak = ''
this.longestStreak = 'Not enough data'
return
}
Expand All @@ -92,6 +107,9 @@ export default {
defaultText() {
return browser.i18n.getMessage('extName')
},
isListEmpty() {
return this.urls.length === 0
},
},
methods: {
openOptionsPage() {
Expand Down
13 changes: 8 additions & 5 deletions src/utils/getHistoryFunctions.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
function getLatestVisitedSite(historyResults = []) {
function getLatestVisitTime(historyResults = []) {
const latestVisitSites = historyResults.flat()

if (latestVisitSites.length === 0) {
return false
}

return latestVisitSites.reduce((prev, current) => {
return prev.lastVisitTime > current.lastVisitTime ? prev : current
})
const timestamps = latestVisitSites
.map(item => item.visitTime)
.sort((a, b) => a - b)

return timestamps[timestamps.length - 1]
}

function getLongestStreak(historyResults = []) {
Expand Down Expand Up @@ -41,4 +44,4 @@ function getLongestStreak(historyResults = []) {
return streak
}

export { getLatestVisitedSite, getLongestStreak }
export { getLatestVisitTime, getLongestStreak }
16 changes: 0 additions & 16 deletions src/utils/mixin.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import { getLongestStreak } from './getHistoryFunctions.js'

export default {
methods: {
async getLongestStreak(urls) {
const urlsPromises = urls.map(url =>
browser.history.getVisits({
url,
})
)

try {
const results = await Promise.all(urlsPromises)
return getLongestStreak(results)
} catch (error) {
console.error(error)
}
},
async getURLListfromStorage() {
try {
const { urls } = await browser.storage.local.get()
Expand Down
12 changes: 6 additions & 6 deletions tests/functions/history.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {
getLatestVisitedSite,
getLatestVisitTime,
getLongestStreak,
} from '../../src/utils/getHistoryFunctions'
import historyItems from '../fixtures/historyItems.json'

import visitItems from '../fixtures/visitItems.json'

it('returns false if there are no history results', () => {
expect(getLatestVisitedSite()).toBe(false)
expect(getLatestVisitedSite([Array(0), Array(0), Array(0)])).toBe(false)
expect(getLatestVisitTime()).toBe(false)
expect(getLatestVisitTime([Array(0), Array(0), Array(0)])).toBe(false)
})

it('returns the latest visited site among the provided urls', () => {
expect(getLatestVisitedSite(historyItems).id).toBe('31583')
it('returns the timestamp of latest visited site among the provided urls', () => {
expect(getLatestVisitTime(visitItems)).toBe(1601749068036.26)
})

it('verifies the properties of the streak object', () => {
Expand Down

0 comments on commit 43ed81c

Please sign in to comment.