Hello from MCP server
<template>
<BaseLayout title="Technician - Profile">
<div class="profile-container">
<h2 class="profile-title">Your Profile</h2>
<!-- User Details Section -->
<div class="section">
<h3 class="section-heading">Your Details</h3>
<div class="details-grid">
<div class="detail-item">
<ion-icon :icon="personOutline" class="detail-icon"></ion-icon>
<div class="detail-content">
<span class="detail-label">Name</span>
<span class="detail-value">{{ user?.name }}</span>
</div>
</div>
<div class="detail-item">
<ion-icon :icon="mailOutline" class="detail-icon"></ion-icon>
<div class="detail-content">
<span class="detail-label">Email</span>
<span class="detail-value">{{ user?.email }}</span>
</div>
</div>
</div>
</div>
<!-- Active Organization Section -->
<div class="section">
<h3 class="section-heading">Your Active Organization</h3>
<div class="details-grid">
<div class="detail-item">
<ion-icon :icon="peopleOutline" class="detail-icon"></ion-icon>
<div class="detail-content">
<span class="detail-label">Organization</span>
<span class="detail-value">{{ activeOrg?.name }}</span>
</div>
<ion-button
fill="clear"
size="small"
@click="navigateTo(`/organization/${activeOrg?.id}`)"
>
<ion-icon slot="icon-only" :icon="eyeOutline"></ion-icon>
</ion-button>
</div>
<div class="detail-item">
<ion-icon :icon="buildOutline" class="detail-icon"></ion-icon>
<div class="detail-content">
<span class="detail-label">Your Roles</span>
<div class="roles-list">
<ion-chip v-for="role in roles" :key="role.id" color="primary">{{ role?.name }}</ion-chip>
</div>
</div>
</div>
<div v-if="roles && roles.length > 1" class="detail-item full-width">
<ion-icon :icon="swapHorizontalOutline" class="detail-icon"></ion-icon>
<div class="detail-content">
<span class="detail-label">Switch Role</span>
<ion-select
:value="tnfrStore.role"
placeholder="Select Role"
@ionChange="tnfrStore.setPreference('role', $event.detail.value)"
class="org-select"
>
<ion-select-option
v-for="role in roles"
:key="role.id"
:value="role.name"
>
{{ role.name }}
</ion-select-option>
</ion-select>
</div>
</div>
<div v-if="availableOrgs.length > 1" class="detail-item full-width">
<ion-icon :icon="swapHorizontalOutline" class="detail-icon"></ion-icon>
<div class="detail-content">
<span class="detail-label">Switch Organization</span>
<ion-select
:value="activeOrg?.id"
placeholder="Select Organization"
@ionChange="switchActiveOrg($event.detail.value)"
class="org-select"
>
<ion-select-option
v-for="org in availableOrgs"
:key="org.id"
:value="org.id"
>
{{ org.name }}
</ion-select-option>
</ion-select>
</div>
</div>
</div>
</div>
<!-- Admin-only sections -->
<template v-if="tnfrStore.role === 'admin'">
<!-- Organization Variables Section -->
<div class="section">
<h3 class="section-heading">Organization Variables</h3>
<p class="section-message">Configure pricing and operational variables for {{ activeOrg?.name }}</p>
<div class="variables-grid">
<div v-for="(value, key) in filteredDisplayVariables" :key="key" class="variable-item">
<div class="variable-content">
<span class="variable-label">{{ key }}</span>
<div v-if="editingVariable !== key" class="variable-display">
<ShowCurrency
v-if="isCurrencyVariable(key)"
:currencyIn="orgVariables[key]"
/>
<span v-else class="variable-value">{{ orgVariables[key] }}</span>
</div>
<ion-input
v-if="editingVariable === key"
:value="value"
placeholder="Enter value"
@ionInput="updateVariable(key, $event.detail.value)"
@ionBlur="stopEditing(key)"
@keyup.enter="stopEditing(key)"
class="variable-input"
></ion-input>
</div>
<div class="variable-actions">
<ion-button
v-if="editingVariable !== key"
fill="clear"
size="small"
color="primary"
@click="startEditing(key)"
>
<ion-icon slot="icon-only" :icon="pencilOutline"></ion-icon>
</ion-button>
<ion-button
v-if="editingVariable === key"
fill="clear"
size="small"
color="success"
@click="stopEditing(key)"
>
<ion-icon slot="icon-only" :icon="checkmarkOutline"></ion-icon>
</ion-button>
</div>
</div>
</div>
</div>
<!-- User Management Section -->
<div class="section">
<h3 class="section-heading">User Management</h3>
<p class="section-message">Manage users and their roles within {{ activeOrg?.name }}</p>
<div class="add-user-wrapper">
<ion-button fill="solid" color="primary" shape="round" class="add-user-btn" @click="showAddEmailsModal = true">
<ion-icon slot="icon-only" :icon="addOutline"></ion-icon>
</ion-button>
</div>
<!-- Add Pre-approved Emails Modal -->
<ion-modal :is-open="showAddEmailsModal" @didDismiss="showAddEmailsModal = false">
<ion-header>
<ion-toolbar>
<ion-title>Pre-approve Emails</ion-title>
<ion-button slot="end" fill="clear" @click="showAddEmailsModal = false">
<ion-icon slot="icon-only" :icon="closeOutline"></ion-icon>
</ion-button>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p class="modal-description">
Enter email addresses to pre-approve for joining this organization.
You can type one email or paste multiple emails (one per line).
</p>
<div class="email-input-section">
<ion-textarea
v-model="emailInput"
placeholder="Enter emails here (one per line)..."
:rows="4"
class="email-textarea"
@keyup.enter="parseEmails"
></ion-textarea>
<ion-button expand="block" @click="parseEmails" :disabled="!emailInput.trim()">
Add Email(s)
</ion-button>
</div>
<div v-if="preApprovedEmails.length > 0" class="emails-list">
<h4 class="emails-list-heading">Pre-approved Emails ({{ preApprovedEmails.length }})</h4>
<div v-for="email in preApprovedEmails" :key="email" class="email-row">
<ion-icon :icon="mailOutline" class="email-row-icon"></ion-icon>
<span class="email-row-text">{{ email }}</span>
<ion-button fill="clear" color="danger" size="small" @click="removeEmail(email)">
<ion-icon slot="icon-only" :icon="trashOutline"></ion-icon>
</ion-button>
</div>
</div>
</ion-content>
</ion-modal>
<ion-loading
:is-open="loadingProfiles"
message="Loading users..."
></ion-loading>
<div v-if="!loadingProfiles && orgProfiles && orgProfiles.length > 0" class="users-grid">
<div v-for="profile in orgProfiles" :key="profile.id" class="user-item">
<div class="user-avatar">
<ion-icon :icon="personOutline"></ion-icon>
</div>
<div class="user-content">
<span class="user-email">{{ (profile.expand as any)?.user?.email || "No email" }}</span>
<span class="user-name">{{ (profile.expand as any)?.user?.name || "Unknown User" }}</span>
</div>
<ion-select
:value="profile.roles"
:multiple="true"
placeholder="Select roles..."
@ionChange="updateUserRoles(profile, $event.detail.value)"
class="user-roles-select"
>
<ion-select-option
v-for="role in availableRoles"
:key="role.id"
:value="role.id"
>
{{ role.name }}
</ion-select-option>
</ion-select>
</div>
</div>
<div v-if="!loadingProfiles && orgProfiles?.length === 0 && preApprovedEmails.length === 0" class="empty-message">
<p>No users found in this organization.</p>
</div>
<!-- Pre-approved emails waiting for signup -->
<div v-if="!loadingProfiles && preApprovedEmails.length > 0" class="users-grid pending-users">
<div v-for="email in preApprovedEmails" :key="email" class="user-item pending">
<div class="user-avatar">
<ion-icon :icon="timeOutline"></ion-icon>
</div>
<div class="user-content">
<span class="user-email">{{ email }}</span>
<span class="user-status">Waiting for user to sign up</span>
</div>
<ion-button fill="clear" size="small" @click="removeEmail(email)">
<ion-icon slot="icon-only" :icon="trashOutline"></ion-icon>
</ion-button>
</div>
</div>
</div>
<!-- Available Roles Section -->
<div class="section">
<h3 class="section-heading">Available Roles</h3>
<p class="section-message">Roles that can be assigned to users</p>
<div v-if="availableRoles && availableRoles.length > 0" class="roles-grid">
<div v-for="role in availableRoles" :key="role.id" class="role-item">
<ion-icon :icon="buildOutline" class="role-icon"></ion-icon>
<span class="role-name">{{ role.name }}</span>
</div>
</div>
<div v-if="availableRoles?.length === 0" class="empty-message">
<p>No roles defined for this organization.</p>
</div>
</div>
<!-- Invite Link Section -->
<div class="section">
<h3 class="section-heading">Invite Link</h3>
<p class="section-message">Share this link for users to request to join the organization</p>
<div class="invite-box">
<pre class="invite-link">https://pricebookplatform.com/organization/{{ activeOrg?.id }}/join</pre>
<ion-button expand="block" color="secondary" @click="copyOrgLink">
Copy Link
</ion-button>
</div>
</div>
</template>
</div>
</BaseLayout>
</template>
<script setup lang="ts">
import { onMounted, ref, computed } from "vue";
import {
IonIcon,
IonChip,
IonSelect,
IonSelectOption,
IonButton,
IonInput,
IonLoading,
IonModal,
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonTextarea,
alertController,
toastController,
} from "@ionic/vue";
import {
addOutline,
buildOutline,
closeOutline,
eyeOutline,
personOutline,
mailOutline,
peopleOutline,
swapHorizontalOutline,
checkmarkOutline,
trashOutline,
timeOutline,
} from "ionicons/icons";
import { mdPencil as pencilOutline } from "@/icons/customIcons";
import { useRouter } from "vue-router";
import { getApi } from "@/dataAccess/getApi";
import BaseLayout from "@/components/BaseLayout.vue";
import ShowCurrency from "@/components/ShowCurrency.vue";
import { useTnfrStore } from "@/stores/tnfr";
import {
convertToBaseCurrency,
convertFromBaseCurrency,
} from "@/utils/currencyConverter";
import { useCurrencyStore } from "@/stores/currency";
import { usePreferencesStore } from "@/stores/preferences";
import {
UsersRecord,
OrganizationsRecord,
ProfilesRecord,
RolesRecord,
ProfilesResponse,
RolesResponse,
} from "@/pocketbase-types";
const user = ref<UsersRecord>();
const activeOrg = ref<OrganizationsRecord>();
const roles = ref<RolesRecord[]>();
const availableOrgs = ref<OrganizationsRecord[]>([]);
// Org management state
const orgVariables = ref<Record<string, any>>({});
const displayVariables = ref<Record<string, any>>({});
const editingVariable = ref<string | null>(null);
const orgProfiles = ref<ProfilesResponse[]>([]);
const availableRoles = ref<RolesResponse[]>([]);
const loadingProfiles = ref(true);
// Pre-approved emails modal state
const showAddEmailsModal = ref(false);
const emailInput = ref("");
const preApprovedEmails = ref<string[]>([]);
const currencyStore = useCurrencyStore();
const preferencesStore = usePreferencesStore();
const tnfrStore = useTnfrStore();
let pb: any = null;
let saveTimeout: ReturnType<typeof setTimeout> | null = null;
const router = useRouter();
// List of variables that should be displayed as currency
const currencyVariables = ["hourlyFee", "serviceCallFee"];
const isCurrencyVariable = (key: string): boolean => {
return currencyVariables.includes(key);
};
// Filter out preApprovedEmails from variables display
const filteredDisplayVariables = computed(() => {
const filtered: Record<string, any> = {};
for (const [key, value] of Object.entries(displayVariables.value)) {
if (key !== 'preApprovedEmails') {
filtered[key] = value;
}
}
return filtered;
});
const navigateTo = (path: string) => {
router.push(path);
};
const switchActiveOrg = async (orgId: string) => {
if (orgId === activeOrg.value?.id) {
return;
}
const selectedOrg = availableOrgs.value.find((org) => org.id === orgId);
const alert = await alertController.create({
header: "Switch Organization",
message: `You are about to switch to "${selectedOrg?.name}". This will log you out and clear all local data. You will need to log back in to continue.`,
buttons: [
{
text: "Cancel",
role: "cancel",
},
{
text: "Switch Organization",
handler: async () => {
await performOrgSwitch(orgId);
},
},
],
});
await alert.present();
};
const performOrgSwitch = async (orgId: string) => {
try {
await pb.collection("users").update(user.value?.id, {
activeOrg: orgId,
});
router.push("/auth/logout");
} catch (error) {
console.error("Failed to switch organization:", error);
}
};
const copyOrgLink = async () => {
try {
const text = `https://pricebookplatform.com/organization/${activeOrg.value?.id}/join`;
await navigator.clipboard.writeText(text);
const toast = await toastController.create({
message: "Invite link copied to clipboard!",
duration: 2000,
color: "success",
});
await toast.present();
} catch (err) {
console.error("Copy failed", err);
const toast = await toastController.create({
message: "Failed to copy link",
duration: 2000,
color: "danger",
});
await toast.present();
}
};
const startEditing = (key: string) => {
editingVariable.value = key;
if (isCurrencyVariable(key)) {
const userCurrencyValue = convertFromBaseCurrency(orgVariables.value[key]);
displayVariables.value[key] = userCurrencyValue;
} else {
displayVariables.value[key] = orgVariables.value[key];
}
};
const stopEditing = async (key: string) => {
if (editingVariable.value !== key) {
return;
}
if (isCurrencyVariable(key)) {
const baseCurrencyValue = convertToBaseCurrency(displayVariables.value[key]);
orgVariables.value[key] = baseCurrencyValue;
} else {
const value = displayVariables.value[key];
if (!isNaN(value) && value !== "" && value !== null) {
orgVariables.value[key] = parseFloat(value);
} else {
orgVariables.value[key] = value;
}
}
editingVariable.value = null;
await saveVariables();
};
const updateVariable = (key: string, value: any) => {
displayVariables.value[key] = value;
};
const saveVariables = async () => {
if (saveTimeout) {
clearTimeout(saveTimeout);
}
saveTimeout = setTimeout(async () => {
try {
await pb.collection("organizations").update(activeOrg.value?.id, {
variables: orgVariables.value,
});
const toast = await toastController.create({
message: "Organization variables updated successfully",
duration: 2000,
color: "success",
});
await toast.present();
} catch (error) {
console.error("Error updating organization variables:", error);
const toast = await toastController.create({
message: "Error updating organization variables",
duration: 3000,
color: "danger",
});
await toast.present();
}
}, 300);
};
const parseEmails = async () => {
if (!emailInput.value.trim()) return;
// Split by newlines, commas, or semicolons, then clean up
const newEmails = emailInput.value
.split(/[\n,;]+/)
.map(email => email.trim().toLowerCase())
.filter(email => {
// Basic email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return email && emailRegex.test(email);
})
.filter(email => !preApprovedEmails.value.includes(email)); // Avoid duplicates
preApprovedEmails.value = [...preApprovedEmails.value, ...newEmails];
emailInput.value = "";
// Save to org variables
orgVariables.value.preApprovedEmails = preApprovedEmails.value;
await saveVariables();
};
const removeEmail = async (email: string) => {
preApprovedEmails.value = preApprovedEmails.value.filter(e => e !== email);
// Save to org variables
orgVariables.value.preApprovedEmails = preApprovedEmails.value;
await saveVariables();
};
const updateUserRoles = async (profile: ProfilesResponse, roleIds: string[]) => {
try {
await pb.collection("profiles").update(profile.id, {
roles: roleIds,
});
const profileIndex = orgProfiles.value.findIndex((p) => p.id === profile.id);
if (profileIndex !== -1) {
orgProfiles.value[profileIndex].roles = roleIds;
}
const toast = await toastController.create({
message: "User roles updated successfully",
duration: 2000,
color: "success",
});
await toast.present();
} catch (error) {
console.error("Error updating user roles:", error);
const toast = await toastController.create({
message: "Error updating user roles",
duration: 3000,
color: "danger",
});
await toast.present();
}
};
onMounted(async () => {
try {
const api = await getApi();
pb = api.pb;
// Initialize currency stores
await preferencesStore.getPreferences();
await currencyStore.getCurrencies();
await currencyStore.getRates();
user.value = pb.authStore.record;
activeOrg.value = pb.authStore.record.expand.activeOrg;
const orgProfile = await api.pb
.collection("profiles")
.getFirstListItem(`user="${user.value?.id}"`, { expand: "roles" });
roles.value = (orgProfile?.expand as any).roles;
const userProfiles = await pb
.collection("profiles")
.getFullList(`user="${user.value?.id}"`, { expand: "org" });
const uniqueOrgs = new Map();
userProfiles.forEach((profile: any) => {
if (profile.expand.org) {
uniqueOrgs.set(profile.expand.org.id, profile.expand.org);
}
});
availableOrgs.value = Array.from(uniqueOrgs.values());
// Load org management data
if (activeOrg.value?.id) {
// Get full organization details with variables
const fullOrg = await pb.collection("organizations").getOne(activeOrg.value.id);
orgVariables.value = fullOrg?.variables || {};
displayVariables.value = { ...orgVariables.value };
// Load pre-approved emails from org variables
preApprovedEmails.value = orgVariables.value.preApprovedEmails || [];
// Get all profiles (users) in this organization
orgProfiles.value = await pb.collection("profiles").getFullList({
filter: `org="${activeOrg.value.id}"`,
expand: "user,roles",
});
// Get all roles available in this organization
availableRoles.value = await pb.collection("roles").getFullList({
filter: `org="${activeOrg.value.id}"`,
});
}
} catch (error) {
console.error("Error loading profile data:", error);
} finally {
loadingProfiles.value = false;
}
});
</script>
<style scoped>
:deep(.ion-page) {
animation: none !important;
transform: none !important;
transition: none !important;
}
.profile-container {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
animation: none !important;
transform: none !important;
transition: none !important;
}
.profile-title {
margin: 0 0 32px 0;
color: var(--ion-text-color);
font-size: 32px;
font-weight: 600;
text-align: center;
font-variant: small-caps;
}
.section {
margin-bottom: 40px;
}
.section-heading {
margin: 0 0 20px 0;
color: var(--ion-text-color);
font-size: 24px;
font-weight: 700;
text-align: center;
}
.details-grid {
display: flex;
flex-direction: column;
gap: 16px;
}
.detail-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background-color: var(--ion-background-color-step-50);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.detail-item.full-width {
flex-direction: column;
align-items: flex-start;
}
.detail-icon {
font-size: 24px;
color: var(--ion-color-primary);
flex-shrink: 0;
}
.detail-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.detail-label {
color: var(--ion-color-medium);
font-size: 14px;
font-weight: 500;
}
.detail-value {
color: var(--ion-text-color);
font-size: 16px;
font-weight: 600;
}
.roles-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 4px;
}
.org-select {
margin-top: 8px;
width: 100%;
max-width: none;
}
.section-message {
margin: 0 0 24px 0;
color: var(--ion-color-medium);
font-size: 16px;
font-style: italic;
text-align: center;
}
.add-user-wrapper {
display: flex;
justify-content: center;
margin-bottom: 24px;
}
.add-user-btn {
--border-radius: 50%;
width: 48px;
height: 48px;
}
/* Pre-approved Emails Modal */
.modal-description {
margin: 0 0 20px 0;
color: var(--ion-color-medium);
font-size: 14px;
line-height: 1.5;
}
.email-input-section {
margin-bottom: 24px;
}
.email-textarea {
margin-bottom: 12px;
background: var(--ion-background-color-step-50);
border-radius: 8px;
--padding-start: 12px;
--padding-end: 12px;
}
.emails-list {
margin-bottom: 24px;
}
.emails-list-heading {
margin: 0 0 12px 0;
font-size: 16px;
font-weight: 600;
color: var(--ion-text-color);
}
.email-row {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: var(--ion-background-color-step-50);
border-radius: 8px;
margin-bottom: 8px;
}
.email-row-icon {
font-size: 20px;
color: var(--ion-color-primary);
flex-shrink: 0;
}
.email-row-text {
flex: 1;
font-size: 14px;
color: var(--ion-text-color);
word-break: break-all;
}
/* Variables Grid */
.variables-grid {
display: flex;
flex-direction: column;
gap: 12px;
}
.variable-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 16px;
background-color: var(--ion-background-color-step-50);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.variable-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
.variable-label {
color: var(--ion-color-medium);
font-size: 14px;
font-weight: 600;
text-transform: capitalize;
}
.variable-display {
color: var(--ion-text-color);
font-size: 18px;
font-weight: 500;
}
.variable-value {
color: var(--ion-text-color);
font-size: 18px;
font-weight: 500;
}
.variable-input {
font-size: 18px;
--padding-start: 0;
--padding-end: 0;
}
.variable-actions {
display: flex;
gap: 8px;
}
/* Users Grid */
.users-grid {
display: flex;
flex-direction: column;
gap: 12px;
}
.user-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background-color: var(--ion-background-color-step-50);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.user-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: var(--ion-color-primary);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.user-avatar ion-icon {
font-size: 24px;
color: white;
}
.user-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.user-email {
color: var(--ion-text-color);
font-size: 16px;
font-weight: 600;
}
.user-name {
color: var(--ion-color-medium);
font-size: 14px;
}
.user-roles-select {
max-width: 200px;
}
/* Pending Users */
.pending-users {
margin-top: 16px;
}
.user-item.pending {
border-style: dashed;
background-color: var(--ion-color-medium);
}
.user-item.pending .user-avatar {
background: var(--ion-color-medium-shade);
}
.user-item.pending .user-avatar ion-icon {
color: var(--ion-color-medium-contrast);
}
.user-item.pending .user-email {
color: var(--ion-color-medium-contrast);
}
.user-item.pending .user-status {
color: var(--ion-color-medium-contrast);
opacity: 0.8;
font-size: 13px;
font-style: italic;
}
.user-item.pending ion-button {
--color: var(--ion-color-medium-contrast);
}
/* Roles Grid */
.roles-grid {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.role-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background-color: var(--ion-background-color-step-50);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.role-icon {
font-size: 20px;
color: var(--ion-color-primary);
}
.role-name {
color: var(--ion-text-color);
font-size: 16px;
font-weight: 500;
}
/* Invite Box */
.invite-box {
max-width: 600px;
margin: 0 auto;
padding: 20px;
background-color: var(--ion-background-color-step-50);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.invite-link {
margin: 0 0 16px 0;
padding: 12px;
background: var(--ion-background-color);
border-radius: 4px;
color: var(--ion-text-color);
font-size: 14px;
word-break: break-all;
white-space: pre-wrap;
}
.empty-message {
text-align: center;
padding: 40px 20px;
color: var(--ion-color-medium);
font-style: italic;
}
/* Mobile adjustments */
@media (max-width: 767px) {
.profile-container {
padding: 16px;
}
.profile-title {
font-size: 28px;
}
.section-heading {
font-size: 20px;
}
.section-message {
font-size: 14px;
}
.detail-item,
.variable-item,
.user-item {
padding: 12px;
}
.detail-icon {
font-size: 20px;
}
.user-avatar {
width: 40px;
height: 40px;
}
.user-avatar ion-icon {
font-size: 20px;
}
.user-roles-select {
max-width: 150px;
}
}
</style>