Merge pull request #3113 from Safelite/rlsmerge/2026.03.26-to-develop
Rlsmerge/2026.03.26 to develop
This commit is contained in:
commit
67a034659d
8 changed files with 117 additions and 95 deletions
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21">
|
|
||||||
<path fill="#E86421" fill-rule="nonzero" d="M10 .5c5.523 0 10 4.477 10 10s-4.477 10-10 10-10-4.477-10-10S4.477.5 10 .5zm.043 13.6a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm.77-9.2h-1.54l-.088.009a.502.502 0 0 0-.299.193.66.66 0 0 0-.125.47l.747 6.806.017.096c.065.249.263.425.495.426l.084-.008c.22-.042.396-.246.427-.51l.793-6.805.004-.102a.651.651 0 0 0-.127-.37.489.489 0 0 0-.388-.205z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 474 B |
|
|
@ -123,6 +123,8 @@ const storeActions = {
|
||||||
|
|
||||||
SAVE_LOGGING_OPTION: "saveLoggingOption",
|
SAVE_LOGGING_OPTION: "saveLoggingOption",
|
||||||
UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError",
|
UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError",
|
||||||
|
GET_VALID_IDEMPOTENCY_KEY: "getValidIdempotencyKey",
|
||||||
|
CORRECT_IDEMPOTENCY_KEY_EXPIRY: "correctIdempotencyKeyExpiry",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { storeActions };
|
export { storeActions };
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ const storeMutations = {
|
||||||
UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited",
|
UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited",
|
||||||
UPDATE_LOGGING_OPTION: "updateLoggingOption",
|
UPDATE_LOGGING_OPTION: "updateLoggingOption",
|
||||||
UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError",
|
UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError",
|
||||||
|
UPDATE_IDEMPOTENCY_KEY: "updateIdempotencyKey",
|
||||||
|
|
||||||
// EXPERIMENT MUTATIONS
|
// EXPERIMENT MUTATIONS
|
||||||
UPDATE_EXPERIMENTS: "updateExperiments",
|
UPDATE_EXPERIMENTS: "updateExperiments",
|
||||||
|
|
|
||||||
|
|
@ -343,14 +343,3 @@ export function splitCMSCopyOnParagraphTag(copy) {
|
||||||
export function splitCMSCopyOnBR(copy) {
|
export function splitCMSCopyOnBR(copy) {
|
||||||
return copy.split("<br>");
|
return copy.split("<br>");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function takes in a number and returns it formatted as USD currency, with or without cents depending on if the number is an integer or not.
|
|
||||||
export function formatToUSDollar(amount) {
|
|
||||||
const isInteger = amount % 1 === 0;
|
|
||||||
return new Intl.NumberFormat("en-US", {
|
|
||||||
style: "currency",
|
|
||||||
currency: "USD",
|
|
||||||
minimumFractionDigits: isInteger ? 0 : 2,
|
|
||||||
maximumFractionDigits: 2,
|
|
||||||
}).format(amount);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ export default {
|
||||||
console.log(`Price = ${this.amountDue}`);
|
console.log(`Price = ${this.amountDue}`);
|
||||||
console.log(`Adyen Price = ${this.adyenPriceTotal}`);
|
console.log(`Adyen Price = ${this.adyenPriceTotal}`);
|
||||||
|
|
||||||
const requestBody = this.getAdyenInitRequestInfo();
|
const requestBody = await this.getAdyenInitRequestInfo();
|
||||||
|
|
||||||
console.log(`Calling with:`);
|
console.log(`Calling with:`);
|
||||||
console.log(requestBody);
|
console.log(requestBody);
|
||||||
|
|
@ -257,6 +257,7 @@ export default {
|
||||||
this.dropinComponent = dropin;
|
this.dropinComponent = dropin;
|
||||||
|
|
||||||
dropin.mount("#adyen-container");
|
dropin.mount("#adyen-container");
|
||||||
|
await this.dispatchStoreAction(storeActions.CORRECT_IDEMPOTENCY_KEY_EXPIRY, expiryTime);
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleCompletedPayment(result) {
|
async handleCompletedPayment(result) {
|
||||||
|
|
@ -438,19 +439,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Now a Method so it is always freshly called and not cached.
|
// Now a Method so it is always freshly called and not cached.
|
||||||
getIdempotencyKey() {
|
async getIdempotencyKey() {
|
||||||
const currentDateTime = new Date();
|
return await this.dispatchStoreAction(storeActions.GET_VALID_IDEMPOTENCY_KEY);
|
||||||
const currentHour = currentDateTime.getUTCHours();
|
|
||||||
const currentDate = currentDateTime.getUTCDate();
|
|
||||||
const id = this?.$store?.getters?.order?.referralCorrelationId;
|
|
||||||
const system = this.sourceSystem;
|
|
||||||
const total = this.adyenPriceTotal;
|
|
||||||
|
|
||||||
return `${id}-${system}-${currentDate}-${currentHour}-${total}`;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Now a Method so it is always freshly called and not cached.
|
// Now a Method so it is always freshly called and not cached.
|
||||||
getAdyenInitRequestInfo() {
|
async getAdyenInitRequestInfo() {
|
||||||
|
const key = await this.getIdempotencyKey();
|
||||||
return {
|
return {
|
||||||
sourceSystem: this.sourceSystem,
|
sourceSystem: this.sourceSystem,
|
||||||
referralSequenceNumber: this.$store.getters.order.referralSequenceNumber,
|
referralSequenceNumber: this.$store.getters.order.referralSequenceNumber,
|
||||||
|
|
@ -464,10 +459,9 @@ export default {
|
||||||
stateOrProvince: this.locationInfo.state,
|
stateOrProvince: this.locationInfo.state,
|
||||||
returnUrl: applicationConfig.PIA_ADYEN_RETURN_URL,
|
returnUrl: applicationConfig.PIA_ADYEN_RETURN_URL,
|
||||||
email: this.$store.getters.order.customer.emailAddress,
|
email: this.$store.getters.order.customer.emailAddress,
|
||||||
IP: "127.0.0.1", // TODO
|
|
||||||
firstName: this.$store.getters.order.customer.firstName,
|
firstName: this.$store.getters.order.customer.firstName,
|
||||||
lastName: this.$store.getters.order.customer.lastName,
|
lastName: this.$store.getters.order.customer.lastName,
|
||||||
idempotencyKey: this.getIdempotencyKey(),
|
idempotencyKey: key,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -81,16 +81,6 @@
|
||||||
cmsWidgetName="AlertNoShopsWidget"
|
cmsWidgetName="AlertNoShopsWidget"
|
||||||
v-if="displayNoShopsAlert"
|
v-if="displayNoShopsAlert"
|
||||||
alertClass="alert-warning" />
|
alertClass="alert-warning" />
|
||||||
<alert
|
|
||||||
ref="alertMSRNotCoveredByInsurance"
|
|
||||||
class="mt-5 mb-5"
|
|
||||||
v-if="isMSRFeeNotCoveredByInsurance"
|
|
||||||
:manualHeadline="MSRFeeAlertHeadlineText"
|
|
||||||
:manualCopy="MSRFeeAlertBodyText"
|
|
||||||
:showWarningIcon="true"
|
|
||||||
:hasBorder="true"
|
|
||||||
:showHorizontalRow="true"
|
|
||||||
alertClass="alert-warning" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
@ -239,11 +229,7 @@ import {
|
||||||
RECAL_ACK_YES,
|
RECAL_ACK_YES,
|
||||||
} from "@/constants/schedule-constants";
|
} from "@/constants/schedule-constants";
|
||||||
|
|
||||||
import {
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
fetchCmsContentForPage,
|
|
||||||
splitCopyOnCMSPlaceHolder,
|
|
||||||
formatToUSDollar,
|
|
||||||
} from "@/helpers/cms-content-helper";
|
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import {
|
import {
|
||||||
getPricedMobileFeePart,
|
getPricedMobileFeePart,
|
||||||
|
|
@ -259,6 +245,7 @@ import { partNumberStrings } from "@/constants/part-number-strings";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
|
||||||
import {
|
import {
|
||||||
calcDaysBetweenDates,
|
calcDaysBetweenDates,
|
||||||
convertDateStringToDate,
|
convertDateStringToDate,
|
||||||
|
|
@ -705,7 +692,8 @@ export default {
|
||||||
isMobileStaticRecalibrationApplicable() {
|
isMobileStaticRecalibrationApplicable() {
|
||||||
return (
|
return (
|
||||||
this.displayMSR &&
|
this.displayMSR &&
|
||||||
this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE
|
this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE &&
|
||||||
|
(this.isCashItacNoComp || this.mobileFeePart?.isInsurable)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
displayMSR() {
|
displayMSR() {
|
||||||
|
|
@ -715,28 +703,6 @@ export default {
|
||||||
?.toLowerCase() === "true"
|
?.toLowerCase() === "true"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
isMSRFeeNotCoveredByInsurance() {
|
|
||||||
return (
|
|
||||||
this.isMobileSelected &&
|
|
||||||
this.isMobileStaticRecalibrationApplicable &&
|
|
||||||
this.mobileFeeHasPrice &&
|
|
||||||
this.isInsurance &&
|
|
||||||
!this.mobileFeePart?.isInsurable
|
|
||||||
);
|
|
||||||
},
|
|
||||||
MSRFeeAlertHeadlineText() {
|
|
||||||
return this.getCmsContent("AlertMSRNotCoveredByInsuranceWidget", "HeadlineText");
|
|
||||||
},
|
|
||||||
MSRFeeAlertBodyText() {
|
|
||||||
const cmsContentText = this.getCmsContent(
|
|
||||||
"AlertMSRNotCoveredByInsuranceWidget",
|
|
||||||
"BodyText"
|
|
||||||
);
|
|
||||||
return cmsContentText.replaceAll(
|
|
||||||
"{custom:mobileFee}",
|
|
||||||
formatToUSDollar(this.mobileFee)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
isCashItacNoComp() {
|
isCashItacNoComp() {
|
||||||
return !this.isInsurance || this.isITAC || this.isNoComp;
|
return !this.isInsurance || this.isITAC || this.isNoComp;
|
||||||
},
|
},
|
||||||
|
|
@ -2054,14 +2020,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async showMultiLocationModal() {
|
async showMultiLocationModal() {
|
||||||
const showMultiLocationAppointment = experimentMixin.methods.getSettingValue(
|
if (!this.selectedRouteCodeData?.routeCode) {
|
||||||
experimentSettings.SHOW_MULTI_LOCATION_APPT
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!this.selectedRouteCodeData?.routeCode &&
|
|
||||||
showMultiLocationAppointment?.toLowerCase() === "true"
|
|
||||||
) {
|
|
||||||
let maxDayRangeToShowPmTimeslot = experimentMixin.methods.getSettingValue(
|
let maxDayRangeToShowPmTimeslot = experimentMixin.methods.getSettingValue(
|
||||||
experimentSettings.SHOW_PM_DAYS_MULTI_LOCATION
|
experimentSettings.SHOW_PM_DAYS_MULTI_LOCATION
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ import {
|
||||||
} from "@/helpers/recal-helper";
|
} from "@/helpers/recal-helper";
|
||||||
import { externalParameterStatus } from "@/constants/external-parameters";
|
import { externalParameterStatus } from "@/constants/external-parameters";
|
||||||
import { experimentSettings } from "@/constants/experiments";
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
import { addPricesToLineItems } from "@/helpers/pricing-helper";
|
import { addPricesToLineItems, getAmountDue } from "@/helpers/pricing-helper";
|
||||||
|
|
||||||
// Export State
|
// Export State
|
||||||
const getDefaultState = () => {
|
const getDefaultState = () => {
|
||||||
|
|
@ -207,6 +207,12 @@ const getDefaultState = () => {
|
||||||
loggingOption: false,
|
loggingOption: false,
|
||||||
hasAlreadyTriggeredError: false,
|
hasAlreadyTriggeredError: false,
|
||||||
},
|
},
|
||||||
|
idempotencyKeyFields: {
|
||||||
|
referralCorrelationId: null,
|
||||||
|
totalInCents: 0,
|
||||||
|
expiryTime: null,
|
||||||
|
idempotencyKey: null,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -862,6 +868,15 @@ export const mutations = {
|
||||||
updateHasTriggeredError(state, hasTriggeredError) {
|
updateHasTriggeredError(state, hasTriggeredError) {
|
||||||
state.applicationUser.hasAlreadyTriggeredError = hasTriggeredError;
|
state.applicationUser.hasAlreadyTriggeredError = hasTriggeredError;
|
||||||
},
|
},
|
||||||
|
updateIdempotencyKey(
|
||||||
|
state,
|
||||||
|
{ idempotencyKey, referralCorrelationId, totalInCents, expiryTime }
|
||||||
|
) {
|
||||||
|
state.idempotencyKeyFields.idempotencyKey = idempotencyKey;
|
||||||
|
state.idempotencyKeyFields.referralCorrelationId = referralCorrelationId;
|
||||||
|
state.idempotencyKeyFields.totalInCents = totalInCents;
|
||||||
|
state.idempotencyKeyFields.expiryTime = expiryTime;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export Getters
|
// Export Getters
|
||||||
|
|
@ -1105,6 +1120,35 @@ export const getters = {
|
||||||
state.order.customer.emailAddress
|
state.order.customer.emailAddress
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isIdempotencyKeyValid: (state) => {
|
||||||
|
if (!state.idempotencyKeyFields?.idempotencyKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const referralCorrelationId = state.order?.referralCorrelationId;
|
||||||
|
if (
|
||||||
|
!referralCorrelationId ||
|
||||||
|
referralCorrelationId !== state.idempotencyKeyFields?.referralCorrelationId
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = getAmountDue(state.order?.lineItems);
|
||||||
|
const totalInCents = Math.round(total * 100);
|
||||||
|
if (totalInCents !== state.idempotencyKeyFields?.totalInCents) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = new Date();
|
||||||
|
const expiryTime = new Date(state.idempotencyKeyFields.expiryTime);
|
||||||
|
if (!expiryTime || expiryTime.getTime() < currentTime.getTime()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all checks pass, then the key is valid.
|
||||||
|
return true;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export Actions
|
// Export Actions
|
||||||
|
|
@ -3665,6 +3709,63 @@ export const actions = {
|
||||||
updateHasTriggeredError(context, hasAlreadyTriggeredError) {
|
updateHasTriggeredError(context, hasAlreadyTriggeredError) {
|
||||||
context.commit(storeMutations.UPDATE_HAS_TRIGGERED_ERROR, hasAlreadyTriggeredError);
|
context.commit(storeMutations.UPDATE_HAS_TRIGGERED_ERROR, hasAlreadyTriggeredError);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getValidIdempotencyKey(context) {
|
||||||
|
if (context.getters.isIdempotencyKeyValid) {
|
||||||
|
return context.state.idempotencyKeyFields.idempotencyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If invalid, need to regenerate.
|
||||||
|
const referralCorrelationId = context.state.order?.referralCorrelationId;
|
||||||
|
if (!referralCorrelationId) {
|
||||||
|
// Can't generate!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = getAmountDue(context.state.order?.lineItems);
|
||||||
|
const totalInCents = Math.round(total * 100);
|
||||||
|
if (Number.isNaN(totalInCents)) {
|
||||||
|
// Can't generate!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = new Date();
|
||||||
|
const nextHour = currentTime.getUTCHours() + 1;
|
||||||
|
currentTime.setUTCHours(nextHour);
|
||||||
|
|
||||||
|
const newId = crypto.randomUUID();
|
||||||
|
|
||||||
|
const newKeyInfo = {
|
||||||
|
idempotencyKey: newId,
|
||||||
|
referralCorrelationId: referralCorrelationId,
|
||||||
|
totalInCents: totalInCents,
|
||||||
|
expiryTime: currentTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
context.commit(storeMutations.UPDATE_IDEMPOTENCY_KEY, newKeyInfo);
|
||||||
|
|
||||||
|
return newId;
|
||||||
|
},
|
||||||
|
|
||||||
|
correctIdempotencyKeyExpiry(context, expiryTime) {
|
||||||
|
if (!context.getters.isIdempotencyKeyValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentExpiryTime = new Date(context.state.idempotencyKeyFields.expiryTime);
|
||||||
|
const expiryTimeAsDate = new Date(expiryTime);
|
||||||
|
|
||||||
|
if (expiryTimeAsDate.getTime() < currentExpiryTime.getTime()) {
|
||||||
|
const existingKey = context.state.idempotencyKeyFields;
|
||||||
|
const newKey = {
|
||||||
|
referralCorrelationId: existingKey.referralCorrelationId,
|
||||||
|
totalInCents: existingKey.totalInCents,
|
||||||
|
idempotencyKey: existingKey.idempotencyKey,
|
||||||
|
expiryTime: expiryTimeAsDate,
|
||||||
|
};
|
||||||
|
context.commit(storeMutations.UPDATE_IDEMPOTENCY_KEY, newKey);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,9 @@
|
||||||
isDismissible ? 'alert-dismissible' : '',
|
isDismissible ? 'alert-dismissible' : '',
|
||||||
this.alertClass,
|
this.alertClass,
|
||||||
this.cssClassNameForCmsWidget,
|
this.cssClassNameForCmsWidget,
|
||||||
this.hasBorder ? 'bordered' : '',
|
|
||||||
]">
|
]">
|
||||||
<p class="mx-6 my-0 fw-bold alert-heading">
|
<p class="mx-6 my-0 fw-bold alert-heading">
|
||||||
<img v-if="showInfoIcon" :src="infoIcon" alt="Info Icon" class="info-icon" />
|
<img v-if="showInfoIcon" :src="infoIcon" alt="Info Icon" class="info-icon" />
|
||||||
<img
|
|
||||||
v-if="showWarningIcon"
|
|
||||||
:src="warningIcon"
|
|
||||||
alt="Warning Icon"
|
|
||||||
class="warning-icon" />
|
|
||||||
{{ alertHeadline }}
|
{{ alertHeadline }}
|
||||||
</p>
|
</p>
|
||||||
<hr v-if="showHorizontalRow" />
|
<hr v-if="showHorizontalRow" />
|
||||||
|
|
@ -69,9 +63,7 @@ export default {
|
||||||
name: "alert",
|
name: "alert",
|
||||||
props: {
|
props: {
|
||||||
showInfoIcon: Boolean,
|
showInfoIcon: Boolean,
|
||||||
showWarningIcon: Boolean,
|
|
||||||
showHorizontalRow: Boolean,
|
showHorizontalRow: Boolean,
|
||||||
hasBorder: Boolean,
|
|
||||||
isDismissible: Boolean,
|
isDismissible: Boolean,
|
||||||
alertClass: String,
|
alertClass: String,
|
||||||
/*
|
/*
|
||||||
|
|
@ -104,9 +96,6 @@ export default {
|
||||||
infoIcon() {
|
infoIcon() {
|
||||||
return require(`@/assets/img/icons/info-circle-blue.svg`);
|
return require(`@/assets/img/icons/info-circle-blue.svg`);
|
||||||
},
|
},
|
||||||
warningIcon() {
|
|
||||||
return require(`@/assets/img/icons/alert-circle-yellow.svg`);
|
|
||||||
},
|
|
||||||
pageQueryString() {
|
pageQueryString() {
|
||||||
return applicationConfig.PAGE_QUERYSTRING;
|
return applicationConfig.PAGE_QUERYSTRING;
|
||||||
},
|
},
|
||||||
|
|
@ -222,19 +211,12 @@ export default {
|
||||||
background-color: $yellow-100;
|
background-color: $yellow-100;
|
||||||
.alert-heading {
|
.alert-heading {
|
||||||
color: $yellow-600;
|
color: $yellow-600;
|
||||||
|
|
||||||
.warning-icon {
|
|
||||||
height: 1rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
svg {
|
svg {
|
||||||
fill: $yellow-600;
|
fill: $yellow-600;
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
hr {
|
|
||||||
border-color: $yellow-800;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&.alert-success {
|
&.alert-success {
|
||||||
background-color: $green-100;
|
background-color: $green-100;
|
||||||
|
|
@ -247,9 +229,6 @@ export default {
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.bordered {
|
|
||||||
border: 1px solid;
|
|
||||||
}
|
|
||||||
& p {
|
& p {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue