Spartan Mode Launch

Spartan Mode Launch
A dragon wrestling with a rocket launch (stable diffusion)

I have launched Spartan Mode officially today! Very happy to launch something properly! I have not actually done that yet. I've put out signup pages etc but not anything where people can just download and use. So thats a nice feeling. The focus will be on doing more projects like this so I can just get people using my stuff and complete things. I'm glad this is completed, it took about 15 days in total. I put it out on Product Hunt a few hours ago. It's my first launch on that site. I'll probably throw it up on indie hackers forum as-well although I have not been contributing to that site. I've heard its best to contribute to conversations on forums if you want to get engagement with the product launch posts. Its also open source project so people can contribute or just use the code as a good React Native/Expo project template:

GitHub - bbsmithy/spartan-mode: Spartan Mode is a mobile app built with React Native and Expo. Its designed to help you track your positive and negative actions and get a score based off of what your actions were each day.
Spartan Mode is a mobile app built with React Native and Expo. Its designed to help you track your positive and negative actions and get a score based off of what your actions were each day. - GitH…

Features

The idea behind Spartan Mode is to track how well you are doing over recent days based off of what you believe to be good and bad actions. Its about taking an honest objective look at your behaviour. Not being dramatic with an overly critical voice (your internal Roy Keane) but looking at things as they are and how they can improve (your internal Jim Gavin).

Actions Tab

The first part of Spartan Mode is the onboarding flow. It has an intro welcome message and then screens for adding 2 positive and one negative actions. The last screen is used for creating your daily reminder notification to fill in your actions report. The actions have positive and negative scores and you can change them and add new ones in the actions tab. Actions are stored in the actions table in sqlite, and saved like this.

export const addAction = (action: { title: string, score: string, positive: boolean }) => async (dispatch) => {
    Database.db?.transaction(tx => {
        const positive = action.positive ? 1 : 0;
        tx.executeSql('INSERT INTO actions (title, score, positive) VALUES (?, ?, ?) ', [action.title, parseInt(action.score), positive])
        tx.executeSql('SELECT * FROM actions WHERE rowid = last_insert_rowid()', [], (_, {rows: { _array }}) => {
            console.log("add", _array[0])
            dispatch(actionsSlice.actions.addAction(_array[0]))
            dispatch(getAllActions())
        })
    }, (err) => {
        console.log({ err })
    })
}

Would definitely recommend using sqlite for projects like this as it allows room for adding more advanced analytics using sql in future.

Today Tab

The today tab is where you track todays actions and you get a score for each day. There is also a reminder setting screen here where you can update your daily report reminder time. The daily_reports table stores all the daily_reports using the expo-sqlite package for storing all the actions and daily_reports data. The action data is stored as a JSON string so as to preserve the action scores for that day (action scores may be updated by user but historical scores should be preserved)

export const completeToday = ({ actions, total_score }:{ actions:[], total_score }) => async (dispatch) => {
    Database.db.transaction(tx => {
        tx.executeSql('INSERT INTO daily_reports (actions, total_score) VALUES (?, ?)', [JSON.stringify(actions), total_score])
        tx.executeSql('SELECT * FROM daily_reports WHERE rowid = last_insert_rowid()', [], (_, {rows: { _array }}) => {
            dispatch(todaySlice.actions.setLastCompletedReport(_array[0]))
            dispatch(getDailyReports())
        })
    }, (err) => {
        console.log({ err })
    })
}

Stats Tab

The stats tab displays your average score and your current spartan ranking. This changes as your average changes and you get a different badge for each ranking level. The average is calculated by the previous days until you get to 10 daily reports. Then it's a 10 day rolling average. This more accurately reflects your recent efforts which helps with developing consistency as you're not plagued by past mistakes.

I may add in "days" filter here to set the number of days the average is calculated over depending on what the user wants. Also a cool feature here would be a graph to plot your daily scores as theres a nice sense of momentum when you see a graph going up. These will hopefully be in the next release...maybe someone reading this would like to build those 👀😉.

The average is calculated when we fetch the last 10 daily_reports like this:

export const getDailyReports = () => async (dispatch, getState) => {
    Database.db.transaction(tx => {
        tx.executeSql('SELECT * FROM daily_reports ORDER BY created_at DESC LIMIT 10', [], (_, {rows: { _array }}) => {
            const recentDays = _array
            const dayCountUsedForAvg = recentDays.length
            const averageScore = Math.round(recentDays.reduce((acc, curr) => acc + curr.total_score, 0) / dayCountUsedForAvg)
            dispatch(spartanSlice.actions.setAverageScore({ score: averageScore, days: dayCountUsedForAvg }))
            dispatch(spartanSlice.actions.setDailyReports(_array))
        })
    }, (err) => {
        console.log({ err })
    })
}

Can add in a param to increase the rows limit value for the days filter in future.

Ranking

I got the Sparta army rankings from ChatGPT so not 100% about historical accuracy but still I like the idea of having progressively more elaborate badges and ranking names changing overtime. It feels nice to level up especially when its based off of real world actions!

Conclusion

Very happy with this project. I like that it was a small quick thing to build but something I'll be using everyday. I like that its open source so that even if people don't benefit from the app itself other people can use the code as a template for their projects or even just pick up ways to do things. Its also just nice to finally finish something fully. My other project Suvnas is a whitelabel app so sort of feels more like a service than a standalone product, but hopefully onbaording more clinics will be motivation for that project.

I will be building a web app this month. I will be writing a planning post in the next few days so stay tuned for more and thanks for reading!

Thanks,

Brian