Page MenuHomePhorge

D1024.1775153860.diff
No OneTemporary

Authored By
Unknown
Size
11 KB
Referenced Files
None
Subscribers
None

D1024.1775153860.diff

diff --git a/src/app/Wallet.php b/src/app/Wallet.php
--- a/src/app/Wallet.php
+++ b/src/app/Wallet.php
@@ -24,7 +24,7 @@
public $timestamps = false;
protected $attributes = [
- 'balance' => 0.00,
+ 'balance' => 0,
'currency' => 'CHF'
];
@@ -37,7 +37,7 @@
];
protected $casts = [
- 'balance' => 'float',
+ 'balance' => 'integer',
];
protected $guarded = ['balance'];
diff --git a/src/resources/js/app.js b/src/resources/js/app.js
--- a/src/resources/js/app.js
+++ b/src/resources/js/app.js
@@ -220,7 +220,7 @@
}
},
price(price) {
- return (price/100).toLocaleString('de-CH', { style: 'currency', currency: 'CHF' })
+ return (price/100).toLocaleString('de-DE', { style: 'currency', currency: 'CHF' })
}
}
})
diff --git a/src/resources/js/routes.js b/src/resources/js/routes.js
--- a/src/resources/js/routes.js
+++ b/src/resources/js/routes.js
@@ -15,6 +15,7 @@
import UserListComponent from '../vue/User/List'
import UserProfileComponent from '../vue/User/Profile'
import UserProfileDeleteComponent from '../vue/User/ProfileDelete'
+import WalletComponent from '../vue/Wallet'
import store from './store'
@@ -85,6 +86,12 @@
component: UserListComponent,
meta: { requiresAuth: true }
},
+ {
+ path: '/wallet',
+ name: 'wallet',
+ component: WalletComponent,
+ meta: { requiresAuth: true }
+ },
{
name: '404',
path: '*',
diff --git a/src/resources/sass/app.scss b/src/resources/sass/app.scss
--- a/src/resources/sass/app.scss
+++ b/src/resources/sass/app.scss
@@ -157,6 +157,12 @@
pointer-events: none;
opacity: 0.6;
}
+
+ .badge {
+ position: absolute;
+ top: .5rem;
+ right: .5rem;
+ }
}
svg {
diff --git a/src/resources/vue/Dashboard.vue b/src/resources/vue/Dashboard.vue
--- a/src/resources/vue/Dashboard.vue
+++ b/src/resources/vue/Dashboard.vue
@@ -24,8 +24,9 @@
<router-link class="card link-users" :to="{ name: 'users' }">
<svg-icon icon="users"></svg-icon><span class="name">User accounts</span>
</router-link>
- <router-link class="card link-wallet disabled" :to="{ name: 'users' }">
+ <router-link class="card link-wallet" :to="{ name: 'wallet' }">
<svg-icon icon="wallet"></svg-icon><span class="name">Wallet</span>
+ <span v-if="balance < 0" class="badge badge-danger">{{ $root.price(balance) }}</span>
</router-link>
</div>
</div>
@@ -36,7 +37,8 @@
data() {
return {
statusProcess: [],
- request: null
+ request: null,
+ balance: 0
}
},
mounted() {
@@ -46,12 +48,14 @@
if (authInfo) {
this.parseStatusInfo(authInfo.statusInfo)
+ this.getBalance(authInfo)
} else {
this.$root.startLoading()
axios.get('/api/auth/info')
.then(response => {
this.$store.state.authInfo = response.data
this.parseStatusInfo(response.data.statusInfo)
+ this.getBalance(response.data)
this.$root.stopLoading()
})
.catch(this.$root.errorHandler)
@@ -82,6 +86,13 @@
})
}, 10000);
}
+ },
+ getBalance(authInfo) {
+ this.balance = 0;
+ // TODO: currencies, multi-wallets, accounts
+ authInfo.wallets.forEach(wallet => {
+ this.balance += wallet.balance
+ })
}
}
}
diff --git a/src/resources/vue/Wallet.vue b/src/resources/vue/Wallet.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/Wallet.vue
@@ -0,0 +1,33 @@
+<template>
+ <div class="container" dusk="wallet-component">
+ <div id="wallet" class="card">
+ <div class="card-body">
+ <div class="card-title">Account balance</div>
+ <div class="card-text">
+ <p>Current account balance is
+ <span :class="balance < 0 ? 'text-danger' : 'text-success'"><strong>{{ $root.price(balance) }}</strong></span>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+ export default {
+ data() {
+ return {
+ balance: 0,
+ }
+ },
+ mounted() {
+ this.balance = 0
+ // TODO: currencies, multi-wallets, accounts
+ this.$store.state.authInfo.wallets.forEach(wallet => {
+ this.balance += wallet.balance
+ })
+ },
+ methods: {
+ }
+ }
+</script>
diff --git a/src/tests/Browser/Pages/Wallet.php b/src/tests/Browser/Pages/Wallet.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Browser/Pages/Wallet.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Tests\Browser\Pages;
+
+use Laravel\Dusk\Page;
+
+class Wallet extends Page
+{
+ /**
+ * Get the URL for the page.
+ *
+ * @return string
+ */
+ public function url(): string
+ {
+ return '/wallet';
+ }
+
+ /**
+ * Assert that the browser is on the page.
+ *
+ * @param \Laravel\Dusk\Browser $browser The browser object
+ *
+ * @return void
+ */
+ public function assert($browser)
+ {
+ $browser->assertPathIs($this->url())
+ ->waitUntilMissing('@app .app-loader')
+ ->assertSeeIn('#wallet .card-title', 'Account balance');
+ }
+
+ /**
+ * Get the element shortcuts for the page.
+ *
+ * @return array
+ */
+ public function elements(): array
+ {
+ return [
+ '@app' => '#app',
+ ];
+ }
+}
diff --git a/src/tests/Browser/UsersTest.php b/src/tests/Browser/UsersTest.php
--- a/src/tests/Browser/UsersTest.php
+++ b/src/tests/Browser/UsersTest.php
@@ -242,7 +242,7 @@
$browser->assertElementsCount('tbody tr', 4)
// groupware SKU
->assertSeeIn('tbody tr:nth-child(1) td.name', 'Groupware Features')
- ->assertSeeIn('tbody tr:nth-child(1) td.price', 'CHF 5.55/month')
+ ->assertSeeIn('tbody tr:nth-child(1) td.price', '5,55 CHF/month')
->assertChecked('tbody tr:nth-child(1) td.selection input')
->assertEnabled('tbody tr:nth-child(1) td.selection input')
->assertTip(
@@ -251,7 +251,7 @@
)
// Mailbox SKU
->assertSeeIn('tbody tr:nth-child(2) td.name', 'User Mailbox')
- ->assertSeeIn('tbody tr:nth-child(2) td.price', 'CHF 4.44/month')
+ ->assertSeeIn('tbody tr:nth-child(2) td.price', '4,44 CHF/month')
->assertChecked('tbody tr:nth-child(2) td.selection input')
->assertDisabled('tbody tr:nth-child(2) td.selection input')
->assertTip(
@@ -260,7 +260,7 @@
)
// Storage SKU
->assertSeeIn('tbody tr:nth-child(3) td.name', 'Storage Quota')
- ->assertSeeIn('tr:nth-child(3) td.price', 'CHF 0.00/month')
+ ->assertSeeIn('tr:nth-child(3) td.price', '0,00 CHF/month')
->assertChecked('tbody tr:nth-child(3) td.selection input')
->assertDisabled('tbody tr:nth-child(3) td.selection input')
->assertTip(
@@ -270,10 +270,10 @@
->with(new QuotaInput('tbody tr:nth-child(3) .range-input'), function ($browser) {
$browser->assertQuotaValue(2)->setQuotaValue(3);
})
- ->assertSeeIn('tr:nth-child(3) td.price', 'CHF 0.25/month')
+ ->assertSeeIn('tr:nth-child(3) td.price', '0,25 CHF/month')
// Test SKU
->assertSeeIn('tbody tr:nth-child(4) td.name', 'Test SKU')
- ->assertSeeIn('tbody tr:nth-child(4) td.price', 'CHF 6.66/month')
+ ->assertSeeIn('tbody tr:nth-child(4) td.price', '6,66 CHF/month')
->assertNotChecked('tbody tr:nth-child(4) td.selection input')
->assertEnabled('tbody tr:nth-child(4) td.selection input')
->assertTip(
diff --git a/src/tests/Browser/WalletTest.php b/src/tests/Browser/WalletTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Browser/WalletTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Tests\Browser;
+
+use App\Wallet;
+use Tests\Browser;
+use Tests\Browser\Pages\Dashboard;
+use Tests\Browser\Pages\Home;
+use Tests\Browser\Pages\Wallet as WalletPage;
+use Tests\TestCaseDusk;
+
+class WalletTest extends TestCaseDusk
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $john = $this->getTestUser('john@kolab.org');
+ Wallet::where('user_id', $john->id)->update(['balance' => -1234]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ $john = $this->getTestUser('john@kolab.org');
+ Wallet::where('user_id', $john->id)->update(['balance' => 0]);
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test wallet page (unauthenticated)
+ */
+ public function testWalletUnauth(): void
+ {
+ // Test that the page requires authentication
+ $this->browse(function (Browser $browser) {
+ $browser->visit('/wallet')->on(new Home());
+ });
+ }
+
+ /**
+ * Test wallet "box" on Dashboard
+ */
+ public function testDashboard(): void
+ {
+ // Test that the page requires authentication
+ $this->browse(function (Browser $browser) {
+ $browser->visit(new Home())
+ ->submitLogon('john@kolab.org', 'simple123', true)
+ ->on(new Dashboard())
+ ->assertSeeIn('@links .link-wallet .name', 'Wallet')
+ ->assertSeeIn('@links .link-wallet .badge', '-12,34 CHF');
+ });
+ }
+
+ /**
+ * Test wallet page
+ *
+ * @depends testDashboard
+ */
+ public function testWallet(): void
+ {
+ $this->browse(function (Browser $browser) {
+ $browser->click('@links .link-wallet')
+ ->on(new WalletPage())
+ ->assertSeeIn('#wallet .card-title', 'Account balance')
+ ->assertSeeIn('#wallet .card-text', 'Current account balance is -12,34 CHF');
+ });
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 2, 6:17 PM (1 d, 9 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18820237
Default Alt Text
D1024.1775153860.diff (11 KB)

Event Timeline