Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117737910
D1024.1775153860.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
11 KB
Referenced Files
None
Subscribers
None
D1024.1775153860.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D1024: Wallet page and wallet balance badge in Dashboard
Attached
Detach File
Event Timeline