Day 195 - Making products based off Google Sheets https://golifelog.com/posts/making-products-based-off-google-sheets-1626230224352
I have a weakness for Google Sheets.
Like today, I was supposed to be doing some marketing for Lifelog, but a fun idea to use Google Sheets as an API for an announcements banner came to me, and I. Just. Had. To. Make. It. And within an hour, the new feature is up. No need to create a new data model or content-type. No backend development required. It’s just so fun and easy to use, as a maker.
Few tools get me this excited and fired up.
Now I’m wondering if I should make an indie product off Google Sheets. Just something that leverages it as a database or CMS. Perhaps I should revive Grublink, a link-in-bio microsite service for F&Bs still at proof-of-concept stage. Or perhaps, I can make a product out of what I just did: announcement banner as a service, via Google Sheets.
So many possibilities, so little time!
Like today, I was supposed to be doing some marketing for Lifelog, but a fun idea to use Google Sheets as an API for an announcements banner came to me, and I. Just. Had. To. Make. It. And within an hour, the new feature is up. No need to create a new data model or content-type. No backend development required. It’s just so fun and easy to use, as a maker.
Few tools get me this excited and fired up.
Now I’m wondering if I should make an indie product off Google Sheets. Just something that leverages it as a database or CMS. Perhaps I should revive Grublink, a link-in-bio microsite service for F&Bs still at proof-of-concept stage. Or perhaps, I can make a product out of what I just did: announcement banner as a service, via Google Sheets.
So many possibilities, so little time!
Day 194 - Are ads unethical? https://golifelog.com/posts/are-ads-unethical-1626140554337
At this (life) stage, I’m finding the advice and success stories of others to be more of an impediment than help. Now I’m open to trying something new, something that more me.
Do what works, don’t do what doesn’t. Try not to annoy people along the way. If it does, try something else.
Simple as that.
Do what works, don’t do what doesn’t. Try not to annoy people along the way. If it does, try something else.
Simple as that.
🧪 Experimenting with a 1-week paid ad campaign on Twitter
New experiment to try paid channels for customer acquisition. I suck at content marketing, so while I continue to work at it, I need some automated help. Social media ads sounds like an obvious thing to try, and with most of my conversion happening on Twitter, I thought I'll give it a go.
Some indie makers think ads are evil and abhor ads like the plague, avoiding it from a moral high horse perspective. I used to think that way, but at this stage, I'm open to try other channels. Many successful SaaS or online businesses use exclusively paid channels, so why not? Is it really *that* unethical to use ads?
Some indie makers think ads are evil and abhor ads like the plague, avoiding it from a moral high horse perspective. I used to think that way, but at this stage, I'm open to try other channels. Many successful SaaS or online businesses use exclusively paid channels, so why not? Is it really *that* unethical to use ads?
Day 193 - Discipline is cheaper than regret https://golifelog.com/posts/discipline-is-cheaper-than-regret-1626053260874
Discipline is cheaper than regret. ~ @ShaneAParrish
Unfortunately, discipline requires a high upfront payment right now, whereas regret is a loan not due in the long term or till old age. Between the immediate discomfort now versus discomfort much much later, is it any wonder why people usually choose the latter?
But they don’t know about compound interest when it comes to regret.
Unfortunately, discipline requires a high upfront payment right now, whereas regret is a loan not due in the long term or till old age. Between the immediate discomfort now versus discomfort much much later, is it any wonder why people usually choose the latter?
But they don’t know about compound interest when it comes to regret.
Day 192 - Is it ok to dream again? https://golifelog.com/posts/is-it-ok-to-dream-again-1625971083677
Is it ok to dream again?
I don’t know, but just asking the question feels nice.
I don’t know, but just asking the question feels nice.
Day 191 - Straight moves https://golifelog.com/posts/straight-moves-1625895523211
Straight moves.
No announcements.
Move in silence.
Allow your energy to speak for itself.
Plot quietly and humbly.
Manifest fruitfully and abundantly.
~ @deandrepage
No announcements.
Move in silence.
Allow your energy to speak for itself.
Plot quietly and humbly.
Manifest fruitfully and abundantly.
~ @deandrepage
Day 190 - More on why advice is overrated https://golifelog.com/posts/more-on-why-advice-is-overrated-1625796335062
* Advice is often just someone disagreeing because you didn't do it *his* way.
* Feedback is a deeper reflection of the person giving it than the person receiving it.
* Advice has the person's own limitations built it. You might be taking on the limitations of others which you might never have had in the first place.
* Advice without skin in the game, when you don't have to face any downsides, is all too easy to give.
* It's easy to give advice where you can't use the advice yourself. A billionaire saying money isn't everything. A beautiful person saying that beauty is on the inside.
* Advice based on one's personal experiences is not representative of reality. It's just a 0.000000001% slice of reality. Certainly not *your* reality.
* Advice based on their success story that sounds too good to be true, usually is. People cherry-pick only the dots they want to connect, not the dots interplaying within the real-world situation they were in. You'll be a victim of their own narrative-fixing if you followed their story.
* Feedback is a deeper reflection of the person giving it than the person receiving it.
* Advice has the person's own limitations built it. You might be taking on the limitations of others which you might never have had in the first place.
* Advice without skin in the game, when you don't have to face any downsides, is all too easy to give.
* It's easy to give advice where you can't use the advice yourself. A billionaire saying money isn't everything. A beautiful person saying that beauty is on the inside.
* Advice based on one's personal experiences is not representative of reality. It's just a 0.000000001% slice of reality. Certainly not *your* reality.
* Advice based on their success story that sounds too good to be true, usually is. People cherry-pick only the dots they want to connect, not the dots interplaying within the real-world situation they were in. You'll be a victim of their own narrative-fixing if you followed their story.
Day 189 - Advice is like yesterday's lottery ticket number https://golifelog.com/posts/advice-is-like-yesterdays-lottery-ticket-number-1625729393032
Advice is seriously over-rated. Especially following seemingly good advice from success stories.
It’s like trying to win the lottery by buying the same winning number from yesterday. It worked yesterday, but it would not work today and most likely wouldn’t work in the future too.
Almost all advice is contextual to the time, place and a network of factors interplaying to produce the result. Even luck.
So here’s a crazy idea:
What if I tried not taking anyone’s advice for a year?
Wouldn’t it be an interesting experiment to stop reading startup or indie hacker success porn, and just act based on my own situation, on real-world feedback and data?
If I were to start on a blank slate without leaning on anyone’s advice, how would I go about it?
It’s like trying to win the lottery by buying the same winning number from yesterday. It worked yesterday, but it would not work today and most likely wouldn’t work in the future too.
Almost all advice is contextual to the time, place and a network of factors interplaying to produce the result. Even luck.
So here’s a crazy idea:
What if I tried not taking anyone’s advice for a year?
Wouldn’t it be an interesting experiment to stop reading startup or indie hacker success porn, and just act based on my own situation, on real-world feedback and data?
If I were to start on a blank slate without leaning on anyone’s advice, how would I go about it?
Tweaked profile page to use .account id instead of author id
• Realised that it's not always the case that the account id will match the author id, so had to change the GET request for `accounts` to use the account id instead of author id
this.$axios.$get(`/acc.../${this.loggedInUser.account}`)
🚨 IMPORTANT to check through tomorrow that all the GET requests for `accounts` is using the accont id instead of author id!!!
this.$axios.$get(`/acc.../${this.loggedInUser.account}`)
🚨 IMPORTANT to check through tomorrow that all the GET requests for `accounts` is using the accont id instead of author id!!!
Added timezone select element to registration page
• Wanted to create a component for this but didn't wanna figure out how to pass data and v-model between the child and parent. So just added the whole block of HTML options into the reg page
• upon registration, I had to in parallel create an `account`, then get the response data in order to then update the `account` id into the `user`'s data:
await this.$axios.post(`endpoint of accounts`).then((res) => {
this.$axios.put(`endpoint of user`, {account: res.id,})})
• upon successful registration, user gets redirected to home page but somehow the sidebar leaderboards were simply not loading. I think the auto-redirect after `this.$auth.loginWith('local',...)` either doesn't trigger $fetch() or mounted(), so the data isn't loading. Had to use a hard refresh `location.reload()` to get the data on the sidebar leaderboards rendering properly. Not elegant, but user likely have to go through this just once in their user lifetime only.
• tweaked TimezoneSelect component in /account page to use new `accounts` endpoint for fetching timezones
• upon registration, I had to in parallel create an `account`, then get the response data in order to then update the `account` id into the `user`'s data:
await this.$axios.post(`endpoint of accounts`).then((res) => {
this.$axios.put(`endpoint of user`, {account: res.id,})})
• upon successful registration, user gets redirected to home page but somehow the sidebar leaderboards were simply not loading. I think the auto-redirect after `this.$auth.loginWith('local',...)` either doesn't trigger $fetch() or mounted(), so the data isn't loading. Had to use a hard refresh `location.reload()` to get the data on the sidebar leaderboards rendering properly. Not elegant, but user likely have to go through this just once in their user lifetime only.
• tweaked TimezoneSelect component in /account page to use new `accounts` endpoint for fetching timezones
Day 188 - 92% sleep https://golifelog.com/posts/92percent-sleep-1625629739695
After a late night debacle the day before, I decided to sleep early last night at 8.13pm. Woke at my usual 4.30am, and my sleep cycle app showed that I achieved that rare above-90s sleep score of 92%!!
So it is possible!
Other benefits I felt:
• Waking up felt easier, didn’t struggle/snooze
• Alertness level upon waking was pretty high - I rated a 7/10 (which I never reached before. Usually it’s 4 or 5)
• Got more energy when working and coding
• Needed breakfast later (inferred that because I was more rested, I had more energy and thus could last longer before the body needed a top-up)
Enshrining this rare achievement in my sleep biohacking journey here.
https://twitter.com/jasonleowsg/status/1412611875385208836?s=21
GO GO GO.
So it is possible!
Other benefits I felt:
• Waking up felt easier, didn’t struggle/snooze
• Alertness level upon waking was pretty high - I rated a 7/10 (which I never reached before. Usually it’s 4 or 5)
• Got more energy when working and coding
• Needed breakfast later (inferred that because I was more rested, I had more energy and thus could last longer before the body needed a top-up)
Enshrining this rare achievement in my sleep biohacking journey here.
https://twitter.com/jasonleowsg/status/1412611875385208836?s=21
GO GO GO.
Congratulations! What app do you use Jason? Sleepcycle.com ? I have been a fitbit user. I am considering getting an apple watch. But don't like the sleep analytics there. I thought it's very very basic there.
Jason Leow
Author
@paras thanks! Yes i use Sleep Cycle. I think it's available on Apple Watch. But been meaning to get an Oura ring for even better sleep tracking (so I heard)
🎉 Added profile images to Top Streaks, Most Streaks, Featured Goals, Just Joined sidebars on home page
• Similar to what I did for `posts` and `accounts`, moved API fetch requests for streaks, goals to fetch() instead - major optimisation fix! No more duplicate data requests to the same API for the respective methods for each leaderboard
• Used the now standard approach of forEach() and push() for the Top Streaks, Most Streaks, Featured Goals, Just Joined leaderboards
• learned that the Strapi object `ctx.state.user.id` is not available in fetch() (and likely aynscData() too)
• Retired the old custom API endpoint, and replaced it with `accounts` endpoint instead
• Added the v-once directive to randomQ() for the writing prompt, so that it just loads twice instead of 4 times(why was it doing that in the first place?!). Ideally should just load once, but due to using v-if-"isAuthenticated" and v-if-"!isAuthenticated", it renders the !isAuth first before rendering the correct isAuth writing prompt.
Only things left now is to create an `account` when registering on the registration page, and updating the TimezoneSelect component to use the new API endpoint...!
• Used the now standard approach of forEach() and push() for the Top Streaks, Most Streaks, Featured Goals, Just Joined leaderboards
• learned that the Strapi object `ctx.state.user.id` is not available in fetch() (and likely aynscData() too)
• Retired the old custom API endpoint, and replaced it with `accounts` endpoint instead
• Added the v-once directive to randomQ() for the writing prompt, so that it just loads twice instead of 4 times(why was it doing that in the first place?!). Ideally should just load once, but due to using v-if-"isAuthenticated" and v-if-"!isAuthenticated", it renders the !isAuth first before rendering the correct isAuth writing prompt.
Only things left now is to create an `account` when registering on the registration page, and updating the TimezoneSelect component to use the new API endpoint...!
Day 187 - Should I hire a VA? https://golifelog.com/posts/should-i-hire-a-va-1625563993148
What percentage of your day is spent on things that you’re uniquely capable of doing? ~ @stephsmithio
I’ve been thinking if I should get some freelance help for my projects. Something like a virtual assistant might be a good first step to try out, to catch the low-hanging work that anyone can easily get up and running quickly.
But of course, delegating isn’t and shouldn’t be the first line of attack. Eliminate, automate, then delegate, they say.
What can I eliminate, automate first, if not then delegate?
I’ve been thinking if I should get some freelance help for my projects. Something like a virtual assistant might be a good first step to try out, to catch the low-hanging work that anyone can easily get up and running quickly.
But of course, delegating isn’t and shouldn’t be the first line of attack. Eliminate, automate, then delegate, they say.
What can I eliminate, automate first, if not then delegate?
Added profile images to posts feed on home page
• Used fetch() to load initial data for `posts` and `accounts`, so that don't have to re-fetch `accounts` data again if loading more posts via
• But using fetch() caused an warning "The client-side rendered virtual DOM tree is not matching server-rendered content." due to v-html for the post excerpt, so had to wrap to v-html
Remaining tasks: to add profile images to Top Streaks, Most Streaks, Featured Goals, Just Joined sidebars!
• But using fetch() caused an warning "The client-side rendered virtual DOM tree is not matching server-rendered content." due to v-html for the post excerpt, so had to wrap
Remaining tasks: to add profile images to Top Streaks, Most Streaks, Featured Goals, Just Joined sidebars!
Day 186 - Sitting is the new smoking https://golifelog.com/posts/sitting-is-the-new-smoking-1625457627105
Thinking of getting a adjustable standing/sitting desk, cooling seat cushions, gamer chair, wrist pads, etc to make my posture better while working.
Any recommendations?
Any recommendations?
Added profile images to posts feed in profile page (which I forgot to do previously)
Added profile images to /posts/_slug page
• Had to add the indiv user's `account` data Object into the `post` Object fetched via asyncData(). Can't use push() as that's for arrays and `post` is an Object.
//my object
var sendData = {field1:value1, field2:value2}
//add element
sendData['field3'] = value3
• because sorted comments is a computed() data, I had to create a mounted() method to first merge-match `accounts` array to `comments` array, using forEach() and push(). Can't do the merging and matching within computed property. Then use the merged array as input to sorted comments computed property.
//my object
var sendData = {field1:value1, field2:value2}
//add element
sendData['field3'] = value3
• because sorted comments is a computed() data, I had to create a mounted() method to first merge-match `accounts` array to `comments` array, using forEach() and push(). Can't do the merging and matching within computed property. Then use the merged array as input to sorted comments computed property.
Day 185 - Your comfort zone is not a good benchmark https://golifelog.com/posts/your-comfort-zone-is-not-a-good-benchmark-1625376771624
When you’re not used to being confident, confidence feels like arrogance. When you’re used to being passive, assertiveness feels like aggression. When you’re not used to getting your needs met, prioritizing yourself feels selfish.
Your comfort zone is not a good benchmark.
~ @JunoCounseling
Your comfort zone is not a good benchmark.
~ @JunoCounseling
Added profile images to /notifications and /_goal pages
• For /notifications page: Used the same approach of using forEach() and push() to match-merge `accounts` array to `notifications` array, in both initial data fetch `fetchNotifs()` and when updating notif class `updateNotifClass()`
• For /_goal pages: Used `try... catch` to prevent error page, in case there's a user without an account and GET request to findOne account fails
• Did you know? In Nuxt.js when using the nuxt/axios plugin, you can also disable the progress bar in specific requests using the progress option in an inline request configuration: https://axios.nuxtjs.org/options/#progress
`this.$axios.$get('URL', { progress: false })`
• For /_goal pages: Used `try... catch` to prevent error page, in case there's a user without an account and GET request to findOne account fails
• Did you know? In Nuxt.js when using the nuxt/axios plugin, you can also disable the progress bar in specific requests using the progress option in an inline request configuration: https://axios.nuxtjs.org/options/#progress
`this.$axios.$get('URL', { progress: false })`
Day 184 - Decision killers: Find 1 decision that removes 100 decisions https://golifelog.com/posts/decision-killers-find-1-decision-that-removes-100-decisions-1625293838922
Tim Ferriss talked about why he won’t be reading any new books in 2020 in his blog post. But the idea that caught my eye was his title:
Finding the one decision that removes 100 decisions
This is a great heuristic to add to my goal of 1% compounding. In matters big or small, life-changing or mundane, find that 1 upstream decision that removes 100 decisions downstream.
Tim elaborates:
In my life, where am I making decisions or saying “yes” out of guilt? Can I create a blanket policy that makes it easier for me to say “no”?
In what areas am I making a lot of decisions, or sending a lot of communication? Are they concentrated anywhere? Can I create a blanket policy that makes it easier for other people to make those decisions?
In what areas am I making a lot of decisions, or sending a lot of communication? Are they concentrated anywhere? Can I create a blanket policy that entirely removes the need to make those decisions?
Finding the one decision that removes 100 decisions
This is a great heuristic to add to my goal of 1% compounding. In matters big or small, life-changing or mundane, find that 1 upstream decision that removes 100 decisions downstream.
Tim elaborates:
In my life, where am I making decisions or saying “yes” out of guilt? Can I create a blanket policy that makes it easier for me to say “no”?
In what areas am I making a lot of decisions, or sending a lot of communication? Are they concentrated anywhere? Can I create a blanket policy that makes it easier for other people to make those decisions?
In what areas am I making a lot of decisions, or sending a lot of communication? Are they concentrated anywhere? Can I create a blanket policy that entirely removes the need to make those decisions?
😅COMPLETED adding profile images for /community page! Had to re-refactor the code again for First Joined, Top, Best, Most Streaks leaderboards
After discovering the more performant approach of using forEach() and push() to add `accounts` details to the original data arrays without having to change the data structure too much, I refactored the code for the previous leaderboards YET AGAIN.
But glad to do so, I guess. Now the code is cleaner, more readable, and more consistent across the methods for each leaderboard. 🤷♂️
And I'm FINALLY done with adding profile images to the /community page! Wow this took a week at least!
😅 Next: adding profile images to /notifications, /_goal, /roadmap, posts/_slug, home pg
But glad to do so, I guess. Now the code is cleaner, more readable, and more consistent across the methods for each leaderboard. 🤷♂️
And I'm FINALLY done with adding profile images to the /community page! Wow this took a week at least!
😅 Next: adding profile images to /notifications, /_goal, /roadmap, posts/_slug, home pg
Day 183 - July https://golifelog.com/posts/july-1625209957787
Looking forward to a fruitfully busy July:
• A training workshop for a polytechnic
• A consultancy project for a government client
• Potential frequent mini-workshops for another government client
So July will be about exercising my gratitude for being able to stay self-employed, by doing these projects well. That’s really my main mission for the month.
But even while I get to do my day job, I’m allocating my early mornings (5-9am) for my other projects, like Lifelog:
• Launching profile images on Lifelog - had spent the past 2 weeks on it, and grossly underestimated the work involved!
• More content marketing for Lifelog - getting back to some regular coding:content candance
• Doing something about my yet-to-be-launched new project Grublink - doing something new had always been life-giving.
Overall, my July goals and plans don’t look like much. It sounds so normal. But frankly, after months of anxiety and chaos, normal actually sounds pretty good to me.
• A training workshop for a polytechnic
• A consultancy project for a government client
• Potential frequent mini-workshops for another government client
So July will be about exercising my gratitude for being able to stay self-employed, by doing these projects well. That’s really my main mission for the month.
But even while I get to do my day job, I’m allocating my early mornings (5-9am) for my other projects, like Lifelog:
• Launching profile images on Lifelog - had spent the past 2 weeks on it, and grossly underestimated the work involved!
• More content marketing for Lifelog - getting back to some regular coding:content candance
• Doing something about my yet-to-be-launched new project Grublink - doing something new had always been life-giving.
Overall, my July goals and plans don’t look like much. It sounds so normal. But frankly, after months of anxiety and chaos, normal actually sounds pretty good to me.
💪 YASSS! Found the best way to merge accounts array with comments and posts array for Most Comments and Most Posts leaderboard on /community page
The most performant way to merge the accounts array with all the leaderboards on the /community page is to use forEach() and push() after using Object.entries() but before splice.sort.slice()
const sortedArr = Object.entries(sorted)
const sortedArrWithAcc = []
sortedArr.forEach(function (element) {
sortedArrWithAcc.push({
id: element[0],
postsArray: element[1],
account: accountsall.find(
(e) => e.author.id === parseInt(element[0])
),
})
})
this.mostPosts = sortedArrWithAcc
.splice(0, 99999)
.sort((a, b) => b.postsArray.length - a.postsArray.length)
.slice(0, 99999)
const sortedArr = Object.entries(sorted)
const sortedArrWithAcc = []
sortedArr.forEach(function (element) {
sortedArrWithAcc.push({
id: element[0],
postsArray: element[1],
account: accountsall.find(
(e) => e.author.id === parseInt(element[0])
),
})
})
this.mostPosts = sortedArrWithAcc
.splice(0, 99999)
.sort((a, b) => b.postsArray.length - a.postsArray.length)
.slice(0, 99999)
Day 182 - Things I started seeing as essential https://golifelog.com/posts/things-i-started-seeing-as-essential-1625126180689
What are some things that you didn’t used to see as essential, but after you started doing them, could no longer live without now?
• Good quality sleep
• Fats and protein
• Some form of daily diet restriction
• Supplements
• Travel
• Habit systems
• Creating new stuff
• Writing regularly/daily
• Frequent me-time for deep work
• Money - crazy right how could I?
• Good quality sleep
• Fats and protein
• Some form of daily diet restriction
• Supplements
• Travel
• Habit systems
• Creating new stuff
• Writing regularly/daily
• Frequent me-time for deep work
• Money - crazy right how could I?
Solved it! Merged accounts array and goals array for Most Goals leaderboard on /community page
Can't use the previous code for merging streaks for the goals array, had to think of something new/creative for the Most Goals leaderboard, fetchMostGoals() function
Ended up flipping the approach, merging each goal (within the raw goals array) with accounts data first using forEach() and push(), then doing the usual of nesting all goals per author together into the data array (`this.mostGoals`) for rendering using for loop and push().
Ended up flipping the approach, merging each goal (within the raw goals array) with accounts data first using forEach() and push(), then doing the usual of nesting all goals per author together into the data array (`this.mostGoals`) for rendering using for loop and push().