-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
45 changed files
with
5,399 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: Build and Publish | ||
on: [ push, pull_request ] | ||
jobs: | ||
build: | ||
name: Test and Build | ||
runs-on: ubuntu-latest | ||
steps: | ||
|
||
# Setup Java 1.8 environment for the next steps | ||
- name: Setup Java | ||
uses: actions/setup-java@v1 | ||
with: | ||
java-version: 1.8 | ||
|
||
# Check out current repository | ||
- name: Fetch Sources | ||
uses: actions/checkout@v2 | ||
|
||
# Build application | ||
- name: Test and Build | ||
run: ./gradlew build | ||
|
||
# If main branch update, deploy to gh-pages | ||
- name: Deploy | ||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' | ||
uses: JamesIves/[email protected] | ||
with: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
BRANCH: gh-pages # The branch the action should deploy to. | ||
FOLDER: build/js/packages/thetax-frontend # The folder the action should deploy. | ||
CLEAN: true # Automatically remove deleted files from the deploy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# thetax.ru | ||
# TheTax.ru | ||
|
||
Tax calculator with a huge reference to https://github.com/stevermeister/dutch-tax-income-calculator. Small playground for @akuleshov7 to play with KotlinJS/React. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
plugins { | ||
java | ||
} | ||
|
||
group = "ru.thetax" | ||
version = "0.0.1" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
plugins { | ||
kotlin("multiplatform") version("2.0.0") | ||
} | ||
|
||
kotlin { | ||
jvm() | ||
js(IR) { | ||
browser() | ||
useCommonJs() | ||
} | ||
|
||
sourceSets { | ||
commonTest.dependencies { | ||
implementation(kotlin("test")) | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
common/src/commonMain/kotlin/ru.thetax/calculator/TaxCalculator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package ru.thetax.calculator | ||
|
||
const val selfEmployedTax = 0.06 | ||
const val nonResidentTax = 0.30 | ||
|
||
data class TaxDetail( | ||
val taxRate: TaxRates, val amount: Double | ||
) | ||
|
||
class TaxCalculator(private val income: Double, isResident: Boolean = true, isSelfEmployed: Boolean = false) { | ||
lateinit var taxDetails: List<TaxDetail> | ||
var totalTax: Double = 0.0 | ||
|
||
init { | ||
when { | ||
isSelfEmployed -> { | ||
totalTax = income * selfEmployedTax | ||
taxDetails = listOf(TaxDetail(TaxRates.SELF_EMPLOYED, income * selfEmployedTax)) | ||
} | ||
|
||
!isResident -> { | ||
totalTax = income * nonResidentTax | ||
taxDetails = listOf(TaxDetail(TaxRates.NON_RESIDENT, income * nonResidentTax)) | ||
} | ||
|
||
else -> calculateTaxForRegularGuy() | ||
} | ||
} | ||
|
||
private fun calculateTaxForRegularGuy() { | ||
var totalTax = 0.0 | ||
var previousLimit = 0.0 | ||
val taxDetails = mutableListOf<TaxDetail>() | ||
|
||
for (rate in TaxRates.entries.toTypedArray().filterNot { it.limit.isNaN() }.sortedBy { it.limit }) { | ||
if (income <= previousLimit) break | ||
val taxableIncome = minOf(income, rate.limit) - previousLimit | ||
val taxAmount = taxableIncome * rate.rate | ||
taxDetails.add(TaxDetail(rate, taxAmount)) | ||
totalTax += taxAmount | ||
previousLimit = rate.limit | ||
} | ||
|
||
this.totalTax = totalTax | ||
this.taxDetails = taxDetails | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
common/src/commonMain/kotlin/ru.thetax/calculator/TaxRates.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package ru.thetax.calculator | ||
|
||
enum class TaxRates(val rate: Double, val limit: Double) { | ||
SELF_EMPLOYED(0.06, Double.NaN), | ||
NON_RESIDENT(0.30, Double.NaN), | ||
RATE_13(0.13, 2400000.0), | ||
RATE_15(0.15,5000000.0), | ||
RATE_18(0.18,20000000.0), | ||
RATE_20(0.20,50000000.0), | ||
RATE_22(0.22, Double.POSITIVE_INFINITY), | ||
} |
22 changes: 22 additions & 0 deletions
22
common/src/commonTest/kotlin/ru.thetax/TaxCalculatorTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package ru.thetax | ||
|
||
import ru.thetax.calculator.TaxCalculator | ||
import ru.thetax.calculator.TaxDetail | ||
import ru.thetax.calculator.TaxRates | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
|
||
class TaxCalculatorTest { | ||
@Test | ||
fun basicScenarios() { | ||
assertEquals(13000.0, TaxCalculator(100000.0).totalTax) | ||
|
||
assertEquals( | ||
listOf( | ||
TaxDetail(TaxRates.RATE_13, 13000.0), | ||
), | ||
|
||
TaxCalculator(100000.0).taxDetails | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import org.jetbrains.kotlin.js.inline.clean.removeDuplicateImports | ||
|
||
plugins { | ||
kotlin("multiplatform") version ("2.0.0") | ||
} | ||
|
||
kotlin { | ||
// https://kotlinlang.org/docs/js-project-setup.html#execution-environments | ||
js(IR) { | ||
browser { | ||
// https://kotlinlang.org/docs/js-project-setup.html#css | ||
commonWebpackConfig { | ||
cssSupport { | ||
enabled.set(true) | ||
} | ||
} | ||
} | ||
// kotlin-wrapper migrates to commonjs and have no @JsNonModule annotations | ||
// https://github.com/JetBrains/kotlin-wrappers/issues/1935 | ||
useCommonJs() | ||
// already default for LEGACY, but explicitly needed for IR: | ||
binaries.executable() | ||
} | ||
|
||
sourceSets { | ||
commonTest.dependencies { | ||
implementation(kotlin("test")) | ||
} | ||
|
||
jsMain.dependencies { | ||
api(project(":common")) | ||
implementation(project.dependencies.enforcedPlatform(libs.kotlin.wrappers.bom)) | ||
implementation("org.jetbrains.kotlin-wrappers:kotlin-react") | ||
implementation("org.jetbrains.kotlin-wrappers:kotlin-extensions") | ||
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom") | ||
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-router-dom") | ||
implementation("org.jetbrains.kotlin-wrappers:kotlin-tanstack-react-table") | ||
|
||
|
||
// ====== unknown technical dependencies | ||
compileOnly(devNpm("sass", "^1.43.0")) | ||
compileOnly(devNpm("sass-loader", "^12.0.0")) | ||
compileOnly(devNpm("style-loader", "^3.3.1")) | ||
compileOnly(devNpm("css-loader", "^6.5.0")) | ||
compileOnly(devNpm("file-loader", "^6.2.0")) | ||
// https://getbootstrap.com/docs/4.0/getting-started/webpack/#importing-precompiled-sass | ||
compileOnly(devNpm("postcss-loader", "^6.2.1")) | ||
compileOnly(devNpm("postcss", "^8.2.13")) | ||
// See https://stackoverflow.com/a/72828500; newer versions are supported only for Bootstrap 5.2+ | ||
compileOnly(devNpm("autoprefixer", "10.4.5")) | ||
compileOnly(devNpm("webpack-bundle-analyzer", "^4.5.0")) | ||
compileOnly(devNpm("mini-css-extract-plugin", "^2.6.0")) | ||
compileOnly(devNpm("html-webpack-plugin", "^5.5.0")) | ||
|
||
implementation(npm("os-browserify", "^0.3.0")) | ||
implementation(npm("path-browserify", "^1.0.1")) | ||
|
||
// ====== used modules ====== | ||
implementation(npm("bootstrap", "5.3.3")) | ||
implementation(npm("react", "^18.0.0")) | ||
implementation(npm("react-dom", "^18.0.0")) | ||
implementation(npm("react-modal", "^3.0.0")) | ||
implementation(npm("@popperjs/core", "2.11.8")) | ||
implementation(npm("animate.css", "^4.1.1")) | ||
// ====== font awesome ====== | ||
implementation(npm("@fortawesome/fontawesome-svg-core", "^1.2.36")) | ||
implementation(npm("@fortawesome/free-solid-svg-icons", "5.15.3")) | ||
implementation(npm("@fortawesome/free-brands-svg-icons", "5.15.3")) | ||
implementation(npm("@fortawesome/react-fontawesome", "^0.1.16")) | ||
} | ||
} | ||
} | ||
|
||
// somehow index.html started to duplicate after I added a common module | ||
// "Entry index.html is a duplicate but no duplicate handling strategy has been set." | ||
tasks.named<Copy>("jsBrowserDistribution") { | ||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE | ||
} | ||
|
||
tasks.withType<org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack> { | ||
// Since we inject timestamp into HTML file, we would like this task to always be re-run. | ||
inputs.property("Build timestamp", System.currentTimeMillis()) | ||
doFirst { | ||
val additionalWebpackResources = fileTree("$buildDir/processedResources/js/main/") { | ||
include("scss/**") | ||
include("index.html") | ||
} | ||
copy { | ||
from(additionalWebpackResources) | ||
into("${rootProject.buildDir}/js/packages/${rootProject.name}-${project.name}") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/** | ||
* Main entrypoint | ||
*/ | ||
|
||
package ru.thetax | ||
|
||
|
||
import js.objects.jso | ||
import react.* | ||
import react.dom.client.createRoot | ||
|
||
import web.dom.document | ||
import web.html.HTMLElement | ||
|
||
import kotlinx.browser.window | ||
import react.router.dom.RouterProvider | ||
import react.router.dom.createBrowserRouter | ||
import ru.thetax.views.taxCalculatorView | ||
|
||
|
||
/** | ||
* Main component for the whole App | ||
*/ | ||
@JsExport | ||
@OptIn(ExperimentalJsExport::class) | ||
val App: FC<Props> = FC { | ||
RouterProvider { | ||
router = createBrowserRouter( | ||
routes = arrayOf( | ||
jso { | ||
path = "/" | ||
element = taxCalculatorView.create() | ||
} | ||
) | ||
) | ||
} | ||
} | ||
|
||
fun main() { | ||
/* Workaround for issue: https://youtrack.jetbrains.com/issue/KT-31888 */ | ||
@Suppress("UnsafeCastFromDynamic") | ||
if (window.asDynamic().__karma__) { | ||
return | ||
} | ||
// this is needed for webpack to include resources | ||
kotlinext.js.require<dynamic>("../scss/tax-app.scss") | ||
// this is needed for webpack to include bootstrap | ||
kotlinext.js.require<dynamic>("bootstrap") | ||
/* ReactModal.setAppElement(document.getElementById("wrapper") as HTMLElement) // required for accessibility in react-modal | ||
initI18n()*/ | ||
val mainDiv = document.getElementById("wrapper") as HTMLElement | ||
createRoot(mainDiv).render(App.create()) | ||
} |
17 changes: 17 additions & 0 deletions
17
frontend/src/jsMain/kotlin/ru/thetax/common/externals/fontawesome/BrandIcons.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** | ||
* External declarations of icons from fontawesome-solid | ||
*/ | ||
|
||
package ru.thetax.common.externals.fontawesome | ||
|
||
@JsModule("@fortawesome/free-brands-svg-icons/faGithub") | ||
@JsNonModule | ||
external val faGithub: FontAwesomeIconModule | ||
|
||
@JsModule("@fortawesome/free-brands-svg-icons/faTwitter") | ||
@JsNonModule | ||
external val faTwitter: FontAwesomeIconModule | ||
|
||
@JsModule("@fortawesome/free-brands-svg-icons/faLinkedinIn") | ||
@JsNonModule | ||
external val faLinkedIn: FontAwesomeIconModule |
10 changes: 10 additions & 0 deletions
10
frontend/src/jsMain/kotlin/ru/thetax/common/externals/fontawesome/FaSetup.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** | ||
* External declarations from fontawesome-svg-core | ||
*/ | ||
|
||
@file:JsModule("@fortawesome/fontawesome-svg-core") | ||
@file:JsNonModule | ||
|
||
package ru.thetax.common.externals.fontawesome | ||
|
||
external val library: dynamic |
15 changes: 15 additions & 0 deletions
15
frontend/src/jsMain/kotlin/ru/thetax/common/externals/fontawesome/FontAwesomeIcon.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
@file:JsModule("@fortawesome/react-fontawesome") | ||
@file:JsNonModule | ||
|
||
package ru.thetax.common.externals.fontawesome | ||
|
||
import react.Component | ||
import react.ReactElement | ||
import react.State | ||
|
||
/** | ||
* External declaration of [FontAwesomeIcon] react component | ||
*/ | ||
external class FontAwesomeIcon : Component<FontAwesomeIconProps, State> { | ||
override fun render(): ReactElement<FontAwesomeIconProps>? | ||
} |
Oops, something went wrong.