Initial commit
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
<script setup>
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
|
||||
const accountData = {
|
||||
avatarImg: avatar1,
|
||||
firstName: 'john',
|
||||
lastName: 'Doe',
|
||||
email: 'johnDoe@example.com',
|
||||
org: 'Pixinvent',
|
||||
phone: '+1 (917) 543-9876',
|
||||
address: '123 Main St, New York, NY 10001',
|
||||
state: 'New York',
|
||||
zip: '10001',
|
||||
country: 'USA',
|
||||
language: 'English',
|
||||
timezone: '(GMT-11:00) International Date Line West',
|
||||
currency: 'USD',
|
||||
}
|
||||
|
||||
const refInputEl = ref()
|
||||
const isConfirmDialogOpen = ref(false)
|
||||
const accountDataLocal = ref(structuredClone(accountData))
|
||||
const isAccountDeactivated = ref(false)
|
||||
const validateAccountDeactivation = [v => !!v || 'Please confirm account deactivation']
|
||||
|
||||
const resetForm = () => {
|
||||
accountDataLocal.value = structuredClone(accountData)
|
||||
}
|
||||
|
||||
const changeAvatar = file => {
|
||||
const fileReader = new FileReader()
|
||||
const { files } = file.target
|
||||
if (files && files.length) {
|
||||
fileReader.readAsDataURL(files[0])
|
||||
fileReader.onload = () => {
|
||||
if (typeof fileReader.result === 'string')
|
||||
accountDataLocal.value.avatarImg = fileReader.result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset avatar image
|
||||
const resetAvatar = () => {
|
||||
accountDataLocal.value.avatarImg = accountData.avatarImg
|
||||
}
|
||||
|
||||
const timezones = [
|
||||
'(GMT-11:00) International Date Line West',
|
||||
'(GMT-11:00) Midway Island',
|
||||
'(GMT-10:00) Hawaii',
|
||||
'(GMT-09:00) Alaska',
|
||||
'(GMT-08:00) Pacific Time (US & Canada)',
|
||||
'(GMT-08:00) Tijuana',
|
||||
'(GMT-07:00) Arizona',
|
||||
'(GMT-07:00) Chihuahua',
|
||||
'(GMT-07:00) La Paz',
|
||||
'(GMT-07:00) Mazatlan',
|
||||
'(GMT-07:00) Mountain Time (US & Canada)',
|
||||
'(GMT-06:00) Central America',
|
||||
'(GMT-06:00) Central Time (US & Canada)',
|
||||
'(GMT-06:00) Guadalajara',
|
||||
'(GMT-06:00) Mexico City',
|
||||
'(GMT-06:00) Monterrey',
|
||||
'(GMT-06:00) Saskatchewan',
|
||||
'(GMT-05:00) Bogota',
|
||||
'(GMT-05:00) Eastern Time (US & Canada)',
|
||||
'(GMT-05:00) Indiana (East)',
|
||||
'(GMT-05:00) Lima',
|
||||
'(GMT-05:00) Quito',
|
||||
'(GMT-04:00) Atlantic Time (Canada)',
|
||||
'(GMT-04:00) Caracas',
|
||||
'(GMT-04:00) La Paz',
|
||||
'(GMT-04:00) Santiago',
|
||||
'(GMT-03:30) Newfoundland',
|
||||
'(GMT-03:00) Brasilia',
|
||||
'(GMT-03:00) Buenos Aires',
|
||||
'(GMT-03:00) Georgetown',
|
||||
'(GMT-03:00) Greenland',
|
||||
'(GMT-02:00) Mid-Atlantic',
|
||||
'(GMT-01:00) Azores',
|
||||
'(GMT-01:00) Cape Verde Is.',
|
||||
'(GMT+00:00) Casablanca',
|
||||
'(GMT+00:00) Dublin',
|
||||
'(GMT+00:00) Edinburgh',
|
||||
'(GMT+00:00) Lisbon',
|
||||
'(GMT+00:00) London',
|
||||
]
|
||||
|
||||
const currencies = [
|
||||
'USD',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CNY',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'INR',
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow>
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardText class="d-flex">
|
||||
<!-- 👉 Avatar -->
|
||||
<VAvatar
|
||||
rounded
|
||||
size="100"
|
||||
class="me-6"
|
||||
:image="accountDataLocal.avatarImg"
|
||||
/>
|
||||
|
||||
<!-- 👉 Upload Photo -->
|
||||
<form class="d-flex flex-column justify-center gap-4">
|
||||
<div class="d-flex flex-wrap gap-4">
|
||||
<VBtn
|
||||
color="primary"
|
||||
size="small"
|
||||
@click="refInputEl?.click()"
|
||||
>
|
||||
<VIcon
|
||||
icon="tabler-cloud-upload"
|
||||
class="d-sm-none"
|
||||
/>
|
||||
<span class="d-none d-sm-block">Upload new photo</span>
|
||||
</VBtn>
|
||||
|
||||
<input
|
||||
ref="refInputEl"
|
||||
type="file"
|
||||
name="file"
|
||||
accept=".jpeg,.png,.jpg,GIF"
|
||||
hidden
|
||||
@input="changeAvatar"
|
||||
>
|
||||
|
||||
<VBtn
|
||||
type="reset"
|
||||
size="small"
|
||||
color="secondary"
|
||||
variant="tonal"
|
||||
@click="resetAvatar"
|
||||
>
|
||||
<span class="d-none d-sm-block">Reset</span>
|
||||
<VIcon
|
||||
icon="tabler-refresh"
|
||||
class="d-sm-none"
|
||||
/>
|
||||
</VBtn>
|
||||
</div>
|
||||
|
||||
<p class="text-body-1 mb-0">
|
||||
Allowed JPG, GIF or PNG. Max size of 800K
|
||||
</p>
|
||||
</form>
|
||||
</VCardText>
|
||||
|
||||
<VCardText class="pt-2">
|
||||
<!-- 👉 Form -->
|
||||
<VForm class="mt-3">
|
||||
<VRow>
|
||||
<!-- 👉 First Name -->
|
||||
<VCol
|
||||
md="6"
|
||||
cols="12"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.firstName"
|
||||
placeholder="John"
|
||||
label="First Name"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Last Name -->
|
||||
<VCol
|
||||
md="6"
|
||||
cols="12"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.lastName"
|
||||
placeholder="Doe"
|
||||
label="Last Name"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Email -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.email"
|
||||
label="E-mail"
|
||||
placeholder="johndoe@gmail.com"
|
||||
type="email"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Organization -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.org"
|
||||
label="Organization"
|
||||
placeholder="Pixinvent"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Phone -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.phone"
|
||||
label="Phone Number"
|
||||
placeholder="+1 (917) 543-9876"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Address -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.address"
|
||||
label="Address"
|
||||
placeholder="123 Main St, New York, NY 10001"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 State -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.state"
|
||||
label="State"
|
||||
placeholder="New York"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Zip Code -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="accountDataLocal.zip"
|
||||
label="Zip Code"
|
||||
placeholder="10001"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Country -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="accountDataLocal.country"
|
||||
label="Country"
|
||||
:items="['USA', 'Canada', 'UK', 'India', 'Australia']"
|
||||
placeholder="Select Country"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Language -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="accountDataLocal.language"
|
||||
label="Language"
|
||||
placeholder="Select Language"
|
||||
:items="['English', 'Spanish', 'Arabic', 'Hindi', 'Urdu']"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Timezone -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="accountDataLocal.timezone"
|
||||
label="Timezone"
|
||||
placeholder="Select Timezone"
|
||||
:items="timezones"
|
||||
:menu-props="{ maxHeight: 200 }"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Currency -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="accountDataLocal.currency"
|
||||
label="Currency"
|
||||
placeholder="Select Currency"
|
||||
:items="currencies"
|
||||
:menu-props="{ maxHeight: 200 }"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Form Actions -->
|
||||
<VCol
|
||||
cols="12"
|
||||
class="d-flex flex-wrap gap-4"
|
||||
>
|
||||
<VBtn>Save changes</VBtn>
|
||||
|
||||
<VBtn
|
||||
color="secondary"
|
||||
variant="tonal"
|
||||
type="reset"
|
||||
@click.prevent="resetForm"
|
||||
>
|
||||
Cancel
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12">
|
||||
<!-- 👉 Delete Account -->
|
||||
<VCard title="Delete Account">
|
||||
<VCardText>
|
||||
<!-- 👉 Checkbox and Button -->
|
||||
<div>
|
||||
<VCheckbox
|
||||
v-model="isAccountDeactivated"
|
||||
:rules="validateAccountDeactivation"
|
||||
label="I confirm my account deactivation"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VBtn
|
||||
:disabled="!isAccountDeactivated"
|
||||
color="error"
|
||||
class="mt-6"
|
||||
@click="isConfirmDialogOpen = true"
|
||||
>
|
||||
Deactivate Account
|
||||
</VBtn>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
<!-- Confirm Dialog -->
|
||||
<ConfirmDialog
|
||||
v-model:is-dialog-visible="isConfirmDialogOpen"
|
||||
confirmation-question="Are you sure you want to deactivate your account?"
|
||||
confirm-title="Deactivated!"
|
||||
confirm-msg="Your account has been deactivated successfully."
|
||||
cancel-title="Cancelled"
|
||||
cancel-msg="Account Deactivation Cancelled!"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,513 @@
|
||||
<script setup>
|
||||
import BillingHistoryTable from './BillingHistoryTable.vue'
|
||||
import mastercard from '@images/icons/payments/mastercard.png'
|
||||
import visa from '@images/icons/payments/visa.png'
|
||||
|
||||
const selectedPaymentMethod = ref('credit-debit-atm-card')
|
||||
const isPricingPlanDialogVisible = ref(false)
|
||||
const isConfirmDialogVisible = ref(false)
|
||||
const isCardEditDialogVisible = ref(false)
|
||||
const isCardDetailSaveBilling = ref(false)
|
||||
|
||||
const creditCards = [
|
||||
{
|
||||
name: 'Tom McBride',
|
||||
number: '5531234567899856',
|
||||
expiry: '12/24',
|
||||
isPrimary: true,
|
||||
type: 'visa',
|
||||
cvv: '456',
|
||||
image: mastercard,
|
||||
},
|
||||
{
|
||||
name: 'Mildred Wagner',
|
||||
number: '4851234567895896',
|
||||
expiry: '10/27',
|
||||
isPrimary: false,
|
||||
type: 'mastercard',
|
||||
cvv: '123',
|
||||
image: visa,
|
||||
},
|
||||
]
|
||||
|
||||
const countryList = [
|
||||
'United States',
|
||||
'Canada',
|
||||
'United Kingdom',
|
||||
'Australia',
|
||||
'New Zealand',
|
||||
'India',
|
||||
'Russia',
|
||||
'China',
|
||||
'Japan',
|
||||
]
|
||||
|
||||
const currentCardDetails = ref()
|
||||
|
||||
const openEditCardDialog = cardDetails => {
|
||||
currentCardDetails.value = cardDetails
|
||||
isCardEditDialogVisible.value = true
|
||||
}
|
||||
|
||||
const cardNumber = ref(135632156548789)
|
||||
const cardName = ref('john Doe')
|
||||
const cardExpiryDate = ref('05/24')
|
||||
const cardCvv = ref(420)
|
||||
|
||||
const resetPaymentForm = () => {
|
||||
cardNumber.value = 135632156548789
|
||||
cardName.value = 'john Doe'
|
||||
cardExpiryDate.value = '05/24'
|
||||
cardCvv.value = 420
|
||||
selectedPaymentMethod.value = 'credit-debit-atm-card'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow>
|
||||
<!-- 👉 Current Plan -->
|
||||
<VCol cols="12">
|
||||
<VCard title="Current Plan">
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<div>
|
||||
<div class="mb-6">
|
||||
<h3 class="text-body-1 text-high-emphasis font-weight-medium mb-1">
|
||||
Your Current Plan is Basic
|
||||
</h3>
|
||||
<p class="text-body-1">
|
||||
A simple start for everyone
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-body-1 text-high-emphasis font-weight-medium mb-1">
|
||||
Active until Dec 09, 2021
|
||||
</h3>
|
||||
<p class="text-body-1">
|
||||
We will send you a notification upon Subscription expiration
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="text-body-1 text-high-emphasis font-weight-medium mb-1">
|
||||
<span class="me-2">$199 Per Month</span>
|
||||
<VChip
|
||||
color="primary"
|
||||
size="small"
|
||||
label
|
||||
>
|
||||
Popular
|
||||
</VChip>
|
||||
</h3>
|
||||
<p class="text-base mb-0">
|
||||
Standard plan for small to medium businesses
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<VAlert
|
||||
icon="tabler-alert-triangle"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
>
|
||||
<VAlertTitle class="mb-1">
|
||||
We need your attention!
|
||||
</VAlertTitle>
|
||||
|
||||
<span>Your plan requires update</span>
|
||||
</VAlert>
|
||||
|
||||
<!-- progress -->
|
||||
<h6 class="d-flex font-weight-medium text-body-1 text-high-emphasis mt-6 mb-1">
|
||||
<span>Days</span>
|
||||
<VSpacer />
|
||||
<span>12 of 30 Days</span>
|
||||
</h6>
|
||||
|
||||
<VProgressLinear
|
||||
color="primary"
|
||||
rounded
|
||||
model-value="15"
|
||||
/>
|
||||
|
||||
<p class="text-body-2 mt-1 mb-0">
|
||||
18 days remaining until your plan requires update
|
||||
</p>
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12">
|
||||
<div class="d-flex flex-wrap gap-4">
|
||||
<VBtn @click="isPricingPlanDialogVisible = true">
|
||||
upgrade plan
|
||||
</VBtn>
|
||||
|
||||
<VBtn
|
||||
color="error"
|
||||
variant="tonal"
|
||||
@click="isConfirmDialogVisible = true"
|
||||
>
|
||||
Cancel Subscription
|
||||
</VBtn>
|
||||
</div>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
<!-- 👉 Confirm Dialog -->
|
||||
<ConfirmDialog
|
||||
v-model:is-dialog-visible="isConfirmDialogVisible"
|
||||
confirmation-question="Are you sure to cancel your subscription?"
|
||||
cancel-msg="Unsubscription Cancelled!!"
|
||||
cancel-title="Cancelled"
|
||||
confirm-msg="Your subscription cancelled successfully."
|
||||
confirm-title="Unsubscribed!"
|
||||
/>
|
||||
|
||||
<!-- 👉 plan and pricing dialog -->
|
||||
<PricingPlanDialog v-model:is-dialog-visible="isPricingPlanDialogVisible" />
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Payment Methods -->
|
||||
<VCol cols="12">
|
||||
<VCard title="Payment Methods">
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<VRow>
|
||||
<!-- 👉 card type switch -->
|
||||
<VCol cols="12">
|
||||
<VRadioGroup
|
||||
v-model="selectedPaymentMethod"
|
||||
inline
|
||||
>
|
||||
<VRadio
|
||||
value="credit-debit-atm-card"
|
||||
label="Credit/Debit/ATM Card"
|
||||
color="primary"
|
||||
class="me-6"
|
||||
/>
|
||||
<VRadio
|
||||
value="paypal-account"
|
||||
label="Paypal account"
|
||||
color="primary"
|
||||
/>
|
||||
</VRadioGroup>
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12">
|
||||
<VRow>
|
||||
<!-- 👉 Card Number -->
|
||||
<VCol cols="12">
|
||||
<AppTextField
|
||||
v-model="cardNumber"
|
||||
label="Card Number"
|
||||
placeholder="1234 1234 1234 1234"
|
||||
type="number"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Name -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="cardName"
|
||||
label="Name"
|
||||
placeholder="John Doe"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Expiry date -->
|
||||
<VCol
|
||||
cols="6"
|
||||
md="3"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="cardExpiryDate"
|
||||
label="Expiry Date"
|
||||
placeholder="MM/YY"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Cvv code -->
|
||||
<VCol
|
||||
cols="6"
|
||||
md="3"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="cardCvv"
|
||||
type="number"
|
||||
label="CVV Code"
|
||||
placeholder="123"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Future Billing switch -->
|
||||
<VCol cols="12">
|
||||
<VSwitch
|
||||
v-model="isCardDetailSaveBilling"
|
||||
density="compact"
|
||||
label="Save card for future billing?"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCol>
|
||||
<VCol
|
||||
cols="12"
|
||||
class="d-flex flex-wrap gap-4"
|
||||
>
|
||||
<VBtn type="submit">
|
||||
Save changes
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="secondary"
|
||||
variant="tonal"
|
||||
@click="resetPaymentForm"
|
||||
>
|
||||
Cancel
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Saved Cards -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<h6 class="text-body-1 text-high-emphasis font-weight-medium mb-6">
|
||||
My Cards
|
||||
</h6>
|
||||
|
||||
<div class="d-flex flex-column gap-y-6">
|
||||
<VCard
|
||||
v-for="card in creditCards"
|
||||
:key="card.name"
|
||||
flat
|
||||
color="rgba(var(--v-theme-on-surface),var(--v-hover-opacity))"
|
||||
>
|
||||
<VCardText class="d-flex flex-sm-row flex-column">
|
||||
<div class="text-no-wrap">
|
||||
<img
|
||||
:src="card.image"
|
||||
height="25"
|
||||
>
|
||||
<h4 class="my-2 text-body-1 text-high-emphasis d-flex align-center">
|
||||
<div class="me-4 font-weight-medium">
|
||||
{{ card.name }}
|
||||
</div>
|
||||
<VChip
|
||||
v-if="card.isPrimary"
|
||||
label
|
||||
color="primary"
|
||||
size="small"
|
||||
>
|
||||
Primary
|
||||
</VChip>
|
||||
</h4>
|
||||
<div class="text-body-1">
|
||||
**** **** **** {{ card.number.substring(card.number.length - 4) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<div class="d-flex flex-column text-sm-end">
|
||||
<div class="d-flex flex-wrap gap-4 order-sm-0 order-1">
|
||||
<VBtn
|
||||
variant="tonal"
|
||||
size="small"
|
||||
@click="openEditCardDialog(card)"
|
||||
>
|
||||
Edit
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="error"
|
||||
size="small"
|
||||
variant="tonal"
|
||||
>
|
||||
Delete
|
||||
</VBtn>
|
||||
</div>
|
||||
<span class="text-body-2 my-4 order-sm-1 order-0">Card expires at {{ card.expiry }}</span>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Add Edit Card Dialog -->
|
||||
<CardAddEditDialog
|
||||
v-model:is-dialog-visible="isCardEditDialogVisible"
|
||||
:card-details="currentCardDetails"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Billing Address -->
|
||||
<VCol cols="12">
|
||||
<VCard title="Billing Address">
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<VRow>
|
||||
<!-- 👉 Company name -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
label="Company Name"
|
||||
placeholder="Pixinvent"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Billing Email -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
label="Billing Email"
|
||||
placeholder="pixinvent@email.com"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Tax ID -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
label="Tax ID"
|
||||
placeholder="123 123 1233"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Vat Number -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
label="VAT Number"
|
||||
placeholder="121212"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Mobile -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
dirty
|
||||
label="Phone Number"
|
||||
type="number"
|
||||
prefix="US (+1)"
|
||||
placeholder="+1 123 456 7890"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Country -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppSelect
|
||||
label="Country"
|
||||
:items="countryList"
|
||||
placeholder="Select Country"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Billing Address -->
|
||||
<VCol cols="12">
|
||||
<AppTextField
|
||||
label="Billing Address"
|
||||
placeholder="1234 Main St"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 State -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
label="State"
|
||||
placeholder="New York"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Zip Code -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
label="Zip Code"
|
||||
type="number"
|
||||
placeholder="100006"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Actions Button -->
|
||||
<VCol
|
||||
cols="12"
|
||||
class="d-flex flex-wrap gap-4"
|
||||
>
|
||||
<VBtn type="submit">
|
||||
Save changes
|
||||
</VBtn>
|
||||
<VBtn
|
||||
type="reset"
|
||||
color="secondary"
|
||||
variant="tonal"
|
||||
>
|
||||
Discard
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Billing History -->
|
||||
<VCol cols="12">
|
||||
<BillingHistoryTable />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.pricing-dialog {
|
||||
.pricing-title {
|
||||
font-size: 1.5rem !important;
|
||||
}
|
||||
|
||||
.v-card {
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,204 @@
|
||||
<script setup>
|
||||
import asana from '@images/icons/brands/asana.png'
|
||||
import behance from '@images/icons/brands/behance.png'
|
||||
import dribbble from '@images/icons/brands/dribbble.png'
|
||||
import facebook from '@images/icons/brands/facebook.png'
|
||||
import github from '@images/icons/brands/github.png'
|
||||
import google from '@images/icons/brands/google.png'
|
||||
import linkedin from '@images/icons/brands/linkedin.png'
|
||||
import mailchimp from '@images/icons/brands/mailchimp.png'
|
||||
import slack from '@images/icons/brands/slack.png'
|
||||
import twitter from '@images/icons/brands/twitter.png'
|
||||
|
||||
const connectedAccounts = ref([
|
||||
{
|
||||
logo: google,
|
||||
name: 'Google',
|
||||
subtitle: 'Calendar and contacts',
|
||||
connected: true,
|
||||
},
|
||||
{
|
||||
logo: slack,
|
||||
name: 'Slack',
|
||||
subtitle: 'Communication',
|
||||
connected: false,
|
||||
},
|
||||
{
|
||||
logo: github,
|
||||
name: 'GitHub',
|
||||
subtitle: 'Manage your Git repositories',
|
||||
connected: true,
|
||||
},
|
||||
{
|
||||
logo: mailchimp,
|
||||
name: 'MailChimp',
|
||||
color: 'yellow',
|
||||
subtitle: 'Email marketing service',
|
||||
connected: true,
|
||||
},
|
||||
{
|
||||
logo: asana,
|
||||
name: 'Asana',
|
||||
subtitle: 'Task management',
|
||||
connected: false,
|
||||
},
|
||||
])
|
||||
|
||||
const socialAccounts = ref([
|
||||
{
|
||||
logo: facebook,
|
||||
name: 'Facebook',
|
||||
connected: false,
|
||||
},
|
||||
{
|
||||
logo: twitter,
|
||||
name: 'Twitter',
|
||||
links: {
|
||||
username: '@Pixinvent',
|
||||
link: 'https://twitter.com/Pixinvents',
|
||||
},
|
||||
connected: true,
|
||||
},
|
||||
{
|
||||
logo: linkedin,
|
||||
name: 'LinkedIn',
|
||||
links: {
|
||||
username: '@Pixinvent',
|
||||
link: 'https://in.linkedin.com/in/pixinvent-creative-studio-561a4713b',
|
||||
},
|
||||
connected: true,
|
||||
},
|
||||
{
|
||||
logo: dribbble,
|
||||
name: 'Dribbble',
|
||||
connected: false,
|
||||
},
|
||||
{
|
||||
logo: behance,
|
||||
name: 'Behance',
|
||||
connected: false,
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
class="pe-md-0 pb-0 pb-md-3"
|
||||
>
|
||||
<!-- 👉 Connected Accounts -->
|
||||
<VCard
|
||||
title="Connected Accounts"
|
||||
subtitle="Display content from your connected accounts on your site"
|
||||
flat
|
||||
>
|
||||
<VCardText>
|
||||
<VList class="card-list">
|
||||
<VListItem
|
||||
v-for="item in connectedAccounts"
|
||||
:key="item.logo"
|
||||
>
|
||||
<template #prepend>
|
||||
<VAvatar>
|
||||
<img
|
||||
:src="item.logo"
|
||||
height="32"
|
||||
>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VListItemTitle>
|
||||
<h6 class="text-h6">
|
||||
{{ item.name }}
|
||||
</h6>
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
{{ item.subtitle }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VListItemAction>
|
||||
<VSwitch
|
||||
v-model="item.connected"
|
||||
density="compact"
|
||||
class="me-1"
|
||||
/>
|
||||
</VListItemAction>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
class="ps-md-0 pt-0 pt-md-3"
|
||||
>
|
||||
<!-- 👉 Social Accounts -->
|
||||
<VCard
|
||||
title="Social Accounts"
|
||||
subtitle="Display content from social accounts on your site"
|
||||
flat
|
||||
>
|
||||
<VCardText>
|
||||
<VList class="card-list">
|
||||
<VListItem
|
||||
v-for="item in socialAccounts"
|
||||
:key="item.logo"
|
||||
>
|
||||
<template #prepend>
|
||||
<VAvatar rounded>
|
||||
<img
|
||||
:src="item.logo"
|
||||
height="32"
|
||||
>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VListItemTitle>
|
||||
<h6 class="text-h6">
|
||||
{{ item.name }}
|
||||
</h6>
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle v-if="item.links?.link">
|
||||
<a
|
||||
:href="item.links.link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ item.links?.username }}</a>
|
||||
</VListItemSubtitle>
|
||||
<VListItemSubtitle
|
||||
v-else
|
||||
class="text-xs"
|
||||
>
|
||||
Not Connected
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VListItemAction>
|
||||
<IconBtn
|
||||
variant="tonal"
|
||||
:color="item.connected ? 'error' : 'secondary'"
|
||||
class="rounded"
|
||||
>
|
||||
<VIcon
|
||||
size="22"
|
||||
:icon="item.connected ? 'tabler-trash' : 'tabler-link' "
|
||||
/>
|
||||
</IconBtn>
|
||||
</VListItemAction>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.card-list {
|
||||
--v-card-list-gap: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<script setup>
|
||||
const recentDevices = ref([
|
||||
{
|
||||
type: 'New for you',
|
||||
email: true,
|
||||
browser: true,
|
||||
app: true,
|
||||
},
|
||||
{
|
||||
type: 'Account activity',
|
||||
email: true,
|
||||
browser: true,
|
||||
app: true,
|
||||
},
|
||||
{
|
||||
type: 'A new browser used to sign in',
|
||||
email: true,
|
||||
browser: true,
|
||||
app: false,
|
||||
},
|
||||
{
|
||||
type: 'A new device is linked',
|
||||
email: true,
|
||||
browser: false,
|
||||
app: false,
|
||||
},
|
||||
])
|
||||
|
||||
const selectedNotification = ref('Only when I\'m online')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>Recent Devices</VCardTitle>
|
||||
<p class="text-body-1 mb-0">
|
||||
We need permission from your browser to show notifications. <span class="text-primary cursor-pointer">Request Permission</span>
|
||||
</p>
|
||||
</VCardItem>
|
||||
|
||||
<VCardText class="px-0">
|
||||
<VDivider />
|
||||
<VTable class="text-no-wrap rounded">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
Type
|
||||
</th>
|
||||
<th scope="col">
|
||||
EMAIL
|
||||
</th>
|
||||
<th scope="col">
|
||||
BROWSER
|
||||
</th>
|
||||
<th scope="col">
|
||||
App
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="device in recentDevices"
|
||||
:key="device.type"
|
||||
>
|
||||
<td class="text-body-1 text-high-emphasis">
|
||||
{{ device.type }}
|
||||
</td>
|
||||
<td>
|
||||
<VCheckbox v-model="device.email" />
|
||||
</td>
|
||||
<td>
|
||||
<VCheckbox v-model="device.browser" />
|
||||
</td>
|
||||
<td>
|
||||
<VCheckbox v-model="device.app" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
<VDivider />
|
||||
</VCardText>
|
||||
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<h6 class="text-body-1 font-weight-medium mb-6">
|
||||
When should we send you notifications?
|
||||
</h6>
|
||||
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedNotification"
|
||||
mandatory
|
||||
placeholder="Select an option"
|
||||
:items="['Only when I\'m online', 'Anytime']"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
<div class="d-flex flex-wrap gap-4 mt-6">
|
||||
<VBtn type="submit">
|
||||
Save Changes
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="secondary"
|
||||
variant="tonal"
|
||||
type="reset"
|
||||
>
|
||||
Discard
|
||||
</VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
@@ -0,0 +1,414 @@
|
||||
<script setup>
|
||||
import laptopGirl from '@images/illustrations/laptop-girl.png'
|
||||
|
||||
const isCurrentPasswordVisible = ref(false)
|
||||
const isNewPasswordVisible = ref(false)
|
||||
const isConfirmPasswordVisible = ref(false)
|
||||
const currentPassword = ref('')
|
||||
const newPassword = ref('')
|
||||
const confirmPassword = ref('')
|
||||
|
||||
const passwordRequirements = [
|
||||
'Minimum 8 characters long - the more, the better',
|
||||
'At least one lowercase character',
|
||||
'At least one number, symbol, or whitespace character',
|
||||
]
|
||||
|
||||
const serverKeys = [
|
||||
{
|
||||
name: 'Server Key 1',
|
||||
key: '23eaf7f0-f4f7-495e-8b86-fad3261282ac',
|
||||
createdOn: '28 Apr 2021, 18:20 GTM+4:10',
|
||||
permission: 'Full Access',
|
||||
},
|
||||
{
|
||||
name: 'Server Key 2',
|
||||
key: 'bb98e571-a2e2-4de8-90a9-2e231b5e99',
|
||||
createdOn: '12 Feb 2021, 10:30 GTM+2:30',
|
||||
permission: 'Read Only',
|
||||
},
|
||||
{
|
||||
name: 'Server Key 3',
|
||||
key: '2e915e59-3105-47f2-8838-6e46bf83b711',
|
||||
createdOn: '28 Dec 2020, 12:21 GTM+4:10',
|
||||
permission: 'Full Access',
|
||||
},
|
||||
]
|
||||
|
||||
const recentDevicesHeaders = [
|
||||
{
|
||||
title: 'BROWSER',
|
||||
key: 'browser',
|
||||
},
|
||||
{
|
||||
title: 'DEVICE',
|
||||
key: 'device',
|
||||
},
|
||||
{
|
||||
title: 'LOCATION',
|
||||
key: 'location',
|
||||
},
|
||||
{
|
||||
title: 'RECENT ACTIVITY',
|
||||
key: 'recentActivity',
|
||||
},
|
||||
]
|
||||
|
||||
const recentDevices = [
|
||||
{
|
||||
browser: 'Chrome on Windows',
|
||||
device: 'HP Spectre 360',
|
||||
location: 'New York, NY',
|
||||
recentActivity: '28 Apr 2022, 18:20',
|
||||
deviceIcon: {
|
||||
icon: 'tabler-brand-windows',
|
||||
color: 'primary',
|
||||
},
|
||||
},
|
||||
{
|
||||
browser: 'Chrome on iPhone',
|
||||
device: 'iPhone 12x',
|
||||
location: 'Los Angeles, CA',
|
||||
recentActivity: '20 Apr 2022, 10:20',
|
||||
deviceIcon: {
|
||||
icon: 'tabler-device-mobile',
|
||||
color: 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
browser: 'Chrome on Android',
|
||||
device: 'Oneplus 9 Pro',
|
||||
location: 'San Francisco, CA',
|
||||
recentActivity: '16 Apr 2022, 04:20',
|
||||
deviceIcon: {
|
||||
icon: 'tabler-brand-android',
|
||||
color: 'success',
|
||||
},
|
||||
},
|
||||
{
|
||||
browser: 'Chrome on macOS',
|
||||
device: 'Apple iMac',
|
||||
location: 'New York, NY',
|
||||
recentActivity: '28 Apr 2022, 18:20',
|
||||
deviceIcon: {
|
||||
icon: 'tabler-brand-apple',
|
||||
color: 'secondary',
|
||||
},
|
||||
},
|
||||
{
|
||||
browser: 'Chrome on Windows',
|
||||
device: 'HP Spectre 360',
|
||||
location: 'Los Angeles, CA',
|
||||
recentActivity: '20 Apr 2022, 10:20',
|
||||
deviceIcon: {
|
||||
icon: 'tabler-brand-windows',
|
||||
color: 'primary',
|
||||
},
|
||||
},
|
||||
{
|
||||
browser: 'Chrome on Android',
|
||||
device: 'Oneplus 9 Pro',
|
||||
location: 'San Francisco, CA',
|
||||
recentActivity: '16 Apr 2022, 04:20',
|
||||
deviceIcon: {
|
||||
icon: 'tabler-brand-android',
|
||||
color: 'success',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const isOneTimePasswordDialogVisible = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow>
|
||||
<!-- SECTION: Change Password -->
|
||||
<VCol cols="12">
|
||||
<VCard title="Change Password">
|
||||
<VForm>
|
||||
<VCardText class="pt-0">
|
||||
<!-- 👉 Current Password -->
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<!-- 👉 current password -->
|
||||
<AppTextField
|
||||
v-model="currentPassword"
|
||||
:type="isCurrentPasswordVisible ? 'text' : 'password'"
|
||||
:append-inner-icon="isCurrentPasswordVisible ? 'tabler-eye-off' : 'tabler-eye'"
|
||||
label="Current Password"
|
||||
autocomplete="on"
|
||||
placeholder="············"
|
||||
@click:append-inner="isCurrentPasswordVisible = !isCurrentPasswordVisible"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
<!-- 👉 New Password -->
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<!-- 👉 new password -->
|
||||
<AppTextField
|
||||
v-model="newPassword"
|
||||
:type="isNewPasswordVisible ? 'text' : 'password'"
|
||||
:append-inner-icon="isNewPasswordVisible ? 'tabler-eye-off' : 'tabler-eye'"
|
||||
label="New Password"
|
||||
autocomplete="on"
|
||||
placeholder="············"
|
||||
@click:append-inner="isNewPasswordVisible = !isNewPasswordVisible"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<!-- 👉 confirm password -->
|
||||
<AppTextField
|
||||
v-model="confirmPassword"
|
||||
:type="isConfirmPasswordVisible ? 'text' : 'password'"
|
||||
:append-inner-icon="isConfirmPasswordVisible ? 'tabler-eye-off' : 'tabler-eye'"
|
||||
label="Confirm New Password"
|
||||
autocomplete="on"
|
||||
placeholder="············"
|
||||
@click:append-inner="isConfirmPasswordVisible = !isConfirmPasswordVisible"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
|
||||
<!-- 👉 Password Requirements -->
|
||||
<VCardText>
|
||||
<h6 class="text-h6 text-medium-emphasis mb-4">
|
||||
Password Requirements:
|
||||
</h6>
|
||||
|
||||
<VList class="card-list">
|
||||
<VListItem
|
||||
v-for="item in passwordRequirements"
|
||||
:key="item"
|
||||
:title="item"
|
||||
class="text-medium-emphasis"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
size="10"
|
||||
icon="tabler-circle-filled"
|
||||
/>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCardText>
|
||||
|
||||
<!-- 👉 Action Buttons -->
|
||||
<VCardText class="d-flex flex-wrap gap-4">
|
||||
<VBtn>Save changes</VBtn>
|
||||
|
||||
<VBtn
|
||||
type="reset"
|
||||
color="secondary"
|
||||
variant="tonal"
|
||||
>
|
||||
Reset
|
||||
</VBtn>
|
||||
</VCardText>
|
||||
</VForm>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<!-- !SECTION -->
|
||||
|
||||
<!-- SECTION Two-steps verification -->
|
||||
<VCol cols="12">
|
||||
<VCard title="Two-steps verification">
|
||||
<VCardText>
|
||||
<h5 class="text-h5 text-medium-emphasis mb-4">
|
||||
Two factor authentication is not enabled yet.
|
||||
</h5>
|
||||
<p class="mb-6">
|
||||
Two-factor authentication adds an additional layer of security to your account by
|
||||
requiring more than just a password to log in.
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="text-decoration-none"
|
||||
>Learn more.</a>
|
||||
</p>
|
||||
|
||||
<VBtn @click="isOneTimePasswordDialogVisible = true">
|
||||
Enable two-factor authentication
|
||||
</VBtn>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<!-- !SECTION -->
|
||||
|
||||
<VCol cols="12">
|
||||
<!-- SECTION: Create an API key -->
|
||||
<VCard title="Create an API key">
|
||||
<VRow no-gutters>
|
||||
<!-- 👉 Choose API Key -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="5"
|
||||
order-md="0"
|
||||
order="1"
|
||||
>
|
||||
<VCardText class="pt-1">
|
||||
<VForm @submit.prevent="() => { }">
|
||||
<VRow>
|
||||
<!-- 👉 Choose API Key -->
|
||||
<VCol cols="12">
|
||||
<AppSelect
|
||||
label="Choose the API key type you want to create"
|
||||
placeholder="Select API key type"
|
||||
:items="['Full Control', 'Modify', 'Read & Execute', 'List Folder Contents', 'Read Only', 'Read & Write']"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Name the API Key -->
|
||||
<VCol cols="12">
|
||||
<AppTextField
|
||||
label="Name the API key"
|
||||
placeholder="Name the API key"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Create Key Button -->
|
||||
<VCol cols="12">
|
||||
<VBtn
|
||||
type="submit"
|
||||
block
|
||||
>
|
||||
Create Key
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Lady image -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="7"
|
||||
order="0"
|
||||
order-md="1"
|
||||
class="d-flex flex-column justify-center align-center"
|
||||
>
|
||||
<VImg
|
||||
:src="laptopGirl"
|
||||
:width="$vuetify.display.smAndDown ? '150' : '200'"
|
||||
:style="$vuetify.display.smAndDown ? 'margin-block-end: 24px' : 'position: absolute; bottom: 0;'"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCard>
|
||||
<!-- !SECTION -->
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12">
|
||||
<!-- SECTION: API Keys List -->
|
||||
<VCard>
|
||||
<VCardItem class="pb-4">
|
||||
<VCardTitle>API Key List & Access</VCardTitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
An API key is a simple encrypted string that identifies an application without any principal. They are useful
|
||||
for accessing public data anonymously, and are used to associate API requests with your project for quota and
|
||||
billing.
|
||||
</VCardText>
|
||||
|
||||
<!-- 👉 Server Status -->
|
||||
<VCardText class="d-flex flex-column gap-y-6">
|
||||
<VCard
|
||||
v-for="serverKey in serverKeys"
|
||||
:key="serverKey.key"
|
||||
flat
|
||||
class="pa-4"
|
||||
color="rgba(var(--v-theme-on-surface),var(--v-hover-opacity))"
|
||||
>
|
||||
<div class="d-flex flex-column gap-y-2">
|
||||
<div class="d-flex align-center flex-wrap">
|
||||
<h5 class="text-h5 me-3">
|
||||
{{ serverKey.name }}
|
||||
</h5>
|
||||
<VChip
|
||||
label
|
||||
color="primary"
|
||||
size="small"
|
||||
>
|
||||
{{ serverKey.permission }}
|
||||
</VChip>
|
||||
</div>
|
||||
<div class="d-flex align-center text-base font-weight-medium">
|
||||
<h6 class="text-h6 text-medium-emphasis me-3">
|
||||
{{ serverKey.key }}
|
||||
</h6>
|
||||
<div class="cursor-pointer">
|
||||
<VIcon
|
||||
icon="tabler-copy"
|
||||
size="20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-disabled">
|
||||
Created on {{ serverKey.createdOn }}
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
<!-- !SECTION -->
|
||||
</VCol>
|
||||
|
||||
<!-- SECTION Recent Devices -->
|
||||
<VCol cols="12">
|
||||
<!-- 👉 Table -->
|
||||
<VCard title="Recent Devices">
|
||||
<VDivider />
|
||||
|
||||
<VDataTable
|
||||
:headers="recentDevicesHeaders"
|
||||
:items="recentDevices"
|
||||
hide-default-footer
|
||||
class="text-no-wrap"
|
||||
>
|
||||
<template #item.browser="{ item }">
|
||||
<div class="d-flex">
|
||||
<VIcon
|
||||
start
|
||||
size="22"
|
||||
:icon="item.deviceIcon.icon"
|
||||
:color="item.deviceIcon.color"
|
||||
/>
|
||||
<div class="text-high-emphasis text-body-1 font-weight-medium">
|
||||
{{ item.browser }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- TODO Refactor this after vuetify provides proper solution for removing default footer -->
|
||||
<template #bottom />
|
||||
</VDataTable>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<!-- !SECTION -->
|
||||
</VRow>
|
||||
|
||||
<!-- SECTION Enable One time password -->
|
||||
<TwoFactorAuthDialog v-model:is-dialog-visible="isOneTimePasswordDialogVisible" />
|
||||
<!-- !SECTION -->
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
--v-card-list-gap: 16px;
|
||||
}
|
||||
|
||||
.server-close-btn {
|
||||
inset-inline-end: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,329 @@
|
||||
<script setup>
|
||||
const searchQuery = ref('')
|
||||
const selectedStatus = ref()
|
||||
const selectedRows = ref([])
|
||||
|
||||
// Data table options
|
||||
const itemsPerPage = ref(10)
|
||||
const page = ref(1)
|
||||
const sortBy = ref()
|
||||
const orderBy = ref()
|
||||
|
||||
const updateOptions = options => {
|
||||
sortBy.value = options.sortBy[0]?.key
|
||||
orderBy.value = options.sortBy[0]?.order
|
||||
}
|
||||
|
||||
// 👉 headers
|
||||
const headers = [
|
||||
{
|
||||
title: '#',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: 'Status',
|
||||
key: 'status',
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
title: 'Client',
|
||||
key: 'client',
|
||||
},
|
||||
{
|
||||
title: 'Total',
|
||||
key: 'total',
|
||||
},
|
||||
{
|
||||
title: 'Issued Date',
|
||||
key: 'date',
|
||||
},
|
||||
{
|
||||
title: 'Balance',
|
||||
key: 'balance',
|
||||
},
|
||||
{
|
||||
title: 'Actions',
|
||||
key: 'actions',
|
||||
sortable: false,
|
||||
},
|
||||
]
|
||||
|
||||
const {
|
||||
data: invoiceData,
|
||||
execute: fetchInvoices,
|
||||
} = await useApi(createUrl('/apps/invoice', {
|
||||
query: {
|
||||
q: searchQuery,
|
||||
status: selectedStatus,
|
||||
itemsPerPage,
|
||||
page,
|
||||
sortBy,
|
||||
orderBy,
|
||||
},
|
||||
}))
|
||||
|
||||
const invoices = computed(() => invoiceData.value?.invoices)
|
||||
const totalInvoices = computed(() => invoiceData.value?.totalInvoices)
|
||||
|
||||
// 👉 Invoice balance variant resolver
|
||||
const resolveInvoiceBalanceVariant = (balance, total) => {
|
||||
if (balance === total)
|
||||
return {
|
||||
status: 'Unpaid',
|
||||
chip: { color: 'error' },
|
||||
}
|
||||
if (balance === 0)
|
||||
return {
|
||||
status: 'Paid',
|
||||
chip: { color: 'success' },
|
||||
}
|
||||
|
||||
return {
|
||||
status: balance,
|
||||
chip: { variant: 'text' },
|
||||
}
|
||||
}
|
||||
|
||||
const resolveInvoiceStatusVariantAndIcon = status => {
|
||||
if (status === 'Partial Payment')
|
||||
return {
|
||||
variant: 'warning',
|
||||
icon: 'tabler-chart-pie',
|
||||
}
|
||||
if (status === 'Paid')
|
||||
return {
|
||||
variant: 'success',
|
||||
icon: 'tabler-check',
|
||||
}
|
||||
if (status === 'Downloaded')
|
||||
return {
|
||||
variant: 'info',
|
||||
icon: 'tabler-arrow-down',
|
||||
}
|
||||
if (status === 'Draft')
|
||||
return {
|
||||
variant: 'primary',
|
||||
icon: 'tabler-folder',
|
||||
}
|
||||
if (status === 'Sent')
|
||||
return {
|
||||
variant: 'secondary',
|
||||
icon: 'tabler-mail',
|
||||
}
|
||||
if (status === 'Past Due')
|
||||
return {
|
||||
variant: 'error',
|
||||
icon: 'tabler-alert-circle',
|
||||
}
|
||||
|
||||
return {
|
||||
variant: 'secondary',
|
||||
icon: 'tabler-x',
|
||||
}
|
||||
}
|
||||
|
||||
const deleteInvoice = async id => {
|
||||
await $api(`/apps/invoice/${ id }`, { method: 'DELETE' })
|
||||
fetchInvoices()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard
|
||||
v-if="invoices"
|
||||
id="invoice-list"
|
||||
title="Billing History"
|
||||
>
|
||||
<VCardText class="d-flex align-center flex-wrap gap-4">
|
||||
<!-- 👉 Create invoice -->
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<VLabel>Show</VLabel>
|
||||
<AppSelect
|
||||
v-model="itemsPerPage"
|
||||
:items="[5, 10, 20, 25, 50]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VBtn
|
||||
prepend-icon="tabler-plus"
|
||||
:to="{ name: 'apps-invoice-add' }"
|
||||
>
|
||||
Create invoice
|
||||
</VBtn>
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<div class="d-flex align-end flex-wrap gap-4">
|
||||
<!-- 👉 Search -->
|
||||
<div class="invoice-list-search">
|
||||
<AppTextField
|
||||
v-model="searchQuery"
|
||||
placeholder="Search Invoice"
|
||||
/>
|
||||
</div>
|
||||
<div class="invoice-list-status">
|
||||
<AppSelect
|
||||
v-model="selectedStatus"
|
||||
placeholder="Invoice Status"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
:items="['Downloaded', 'Draft', 'Sent', 'Paid', 'Partial Payment', 'Past Due']"
|
||||
style="inline-size: 12rem;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
|
||||
<VDivider />
|
||||
|
||||
<!-- SECTION DataTable -->
|
||||
<VDataTableServer
|
||||
v-model="selectedRows"
|
||||
v-model:items-per-page="itemsPerPage"
|
||||
v-model:page="page"
|
||||
show-select
|
||||
:items-length="totalInvoices"
|
||||
:headers="headers"
|
||||
:items="invoices"
|
||||
class="text-no-wrap"
|
||||
@update:options="updateOptions"
|
||||
>
|
||||
<!-- id -->
|
||||
<template #item.id="{ item }">
|
||||
<div class="text-body-1">
|
||||
<RouterLink :to="{ name: 'apps-invoice-preview-id', params: { id: item.id } }">
|
||||
#{{ item.id }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- status -->
|
||||
<template #item.status="{ item }">
|
||||
<VTooltip>
|
||||
<template #activator="{ props }">
|
||||
<VAvatar
|
||||
:size="28"
|
||||
v-bind="props"
|
||||
:color="resolveInvoiceStatusVariantAndIcon(item.invoiceStatus).variant"
|
||||
variant="tonal"
|
||||
>
|
||||
<VIcon
|
||||
size="16"
|
||||
:icon="resolveInvoiceStatusVariantAndIcon(item.invoiceStatus).icon"
|
||||
/>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<p class="mb-0">
|
||||
{{ item.invoiceStatus }}
|
||||
</p>
|
||||
<p class="mb-0">
|
||||
Balance: {{ item.balance }}
|
||||
</p>
|
||||
<p class="mb-0">
|
||||
Due date: {{ item.dueDate }}
|
||||
</p>
|
||||
</VTooltip>
|
||||
</template>
|
||||
|
||||
<!-- client -->
|
||||
<template #item.client="{ item }">
|
||||
<div class="d-flex align-center">
|
||||
<VAvatar
|
||||
size="34"
|
||||
:color="!item.avatar.length ? resolveInvoiceStatusVariantAndIcon(item.invoiceStatus).variant : undefined"
|
||||
:variant="!item.avatar.length ? 'tonal' : undefined"
|
||||
class="me-3"
|
||||
>
|
||||
<VImg
|
||||
v-if="item.avatar.length"
|
||||
:src="item.avatar"
|
||||
/>
|
||||
<span v-else>{{ avatarText(item.client.name) }}</span>
|
||||
</VAvatar>
|
||||
<div class="d-flex flex-column">
|
||||
<RouterLink
|
||||
class="font-weight-medium text-body-1 text-high-emphasis mb-0 text-link"
|
||||
:to="{ name: 'pages-user-profile-tab', params: { tab: 'profile' } }"
|
||||
>
|
||||
{{ item.client.name }}
|
||||
</RouterLink>
|
||||
<span class="text-body-2">{{ item.client.companyEmail }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Total -->
|
||||
<template #item.total="{ item }">
|
||||
${{ item.total }}
|
||||
</template>
|
||||
|
||||
<!-- Issued Date -->
|
||||
<template #item.date="{ item }">
|
||||
{{ item.issuedDate }}
|
||||
</template>
|
||||
|
||||
<!-- Balance -->
|
||||
<template #item.balance="{ item }">
|
||||
<VChip
|
||||
v-if="typeof ((resolveInvoiceBalanceVariant(item.balance, item.total)).status) === 'string'"
|
||||
:color="resolveInvoiceBalanceVariant(item.balance, item.total).chip.color"
|
||||
size="small"
|
||||
label
|
||||
>
|
||||
{{ (resolveInvoiceBalanceVariant(item.balance, item.total)).status }}
|
||||
</VChip>
|
||||
<div
|
||||
v-else
|
||||
class="text-body-1 text-high-emphasis"
|
||||
>
|
||||
{{ Number((resolveInvoiceBalanceVariant(item.balance, item.total)).status) > 0 ? `$${(resolveInvoiceBalanceVariant(item.balance, item.total)).status}` : `-$${Math.abs(Number((resolveInvoiceBalanceVariant(item.balance, item.total)).status))}` }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Actions -->
|
||||
<template #item.actions="{ item }">
|
||||
<IconBtn @click="deleteInvoice(item.id)">
|
||||
<VIcon
|
||||
icon="tabler-trash"
|
||||
size="20"
|
||||
/>
|
||||
</IconBtn>
|
||||
|
||||
<IconBtn :to="{ name: 'apps-invoice-preview-id', params: { id: item.id } }">
|
||||
<VIcon
|
||||
icon="tabler-eye"
|
||||
size="20"
|
||||
/>
|
||||
</IconBtn>
|
||||
<IconBtn>
|
||||
<VIcon
|
||||
icon="tabler-dots-vertical"
|
||||
size="20"
|
||||
/>
|
||||
</IconBtn>
|
||||
</template>
|
||||
|
||||
<template #bottom>
|
||||
<TablePagination
|
||||
v-model:page="page"
|
||||
:items-per-page="itemsPerPage"
|
||||
:total-items="totalInvoices"
|
||||
/>
|
||||
</template>
|
||||
</VDataTableServer>
|
||||
<!-- !SECTION -->
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
#invoice-list {
|
||||
.invoice-list-actions {
|
||||
inline-size: 8rem;
|
||||
}
|
||||
|
||||
.invoice-list-search {
|
||||
inline-size: 12rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user