Skip to content

Commit

Permalink
Improve session info discoverability (evcc-io#9783)
Browse files Browse the repository at this point in the history
  • Loading branch information
naltatis authored Sep 9, 2023
1 parent 6f7e45d commit 5ef8825
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 126 deletions.
16 changes: 10 additions & 6 deletions assets/js/components/LabelAndValue.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<template>
<div class="root">
<div class="mb-2 label" :class="labelClass">{{ label }}</div>
<div class="mb-2 label" :class="labelClass">
<slot name="label">{{ label }}</slot>
</div>
<slot>
<h3 class="value m-0 d-block d-sm-flex align-items-baseline" :class="valueClass">
<AnimatedNumber v-if="valueFmt" :to="value" :format="valueFmt" />
<span v-else>{{ value }}</span>
<div v-if="extraValue" class="extraValue ms-0 ms-sm-1 text-nowrap">
{{ extraValue }}
</div>
<slot name="value">
<AnimatedNumber v-if="valueFmt" :to="value" :format="valueFmt" />
<span v-else>{{ value }}</span>
<div v-if="extraValue" class="extraValue ms-0 ms-sm-1 text-nowrap">
{{ extraValue }}
</div>
</slot>
</h3>
</slot>
</div>
Expand Down
103 changes: 6 additions & 97 deletions assets/js/components/Loadpoint.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,66 +78,7 @@
:value="fmtEnergy(chargedEnergy)"
align="center"
/>
<div class="sessionInfo" @click="nextSessionInfo">
<LabelAndValue
v-if="sessionInfo === SESSION.SOLAR"
:label="$t('main.loadpoint.solar')"
:value="sessionSolarPercentage"
:valueFmt="fmtSolar"
align="end"
/>
<div v-else-if="sessionInfo === SESSION.AVG_PRICE">
<LabelAndValue
class="d-block d-sm-none"
:label="$t('main.loadpoint.avgPrice')"
:value="sessionPricePerKWh"
:valueFmt="fmtAvgPriceShort"
align="end"
/>
<LabelAndValue
class="d-none d-sm-block"
:label="$t('main.loadpoint.avgPrice')"
:value="sessionPricePerKWh"
:valueFmt="fmtAvgPrice"
align="end"
/>
</div>
<LabelAndValue
v-else-if="sessionInfo === SESSION.PRICE"
:label="$t('main.loadpoint.price')"
:value="sessionPrice"
:valueFmt="fmtPrice"
align="end"
/>
<div v-else-if="sessionInfo === SESSION.CO2">
<LabelAndValue
class="d-block d-sm-none"
:label="$t('main.loadpoint.co2')"
:value="sessionCo2PerKWh"
:valueFmt="fmtCo2Short"
align="end"
/>
<LabelAndValue
class="d-none d-sm-block"
:label="$t('main.loadpoint.co2')"
:value="sessionCo2PerKWh"
:valueFmt="fmtCo2Medium"
align="end"
/>
</div>
<LabelAndValue
v-else-if="chargeRemainingDurationInterpolated"
:label="$t('main.loadpoint.remaining')"
:value="fmtDuration(chargeRemainingDurationInterpolated)"
align="end"
/>
<LabelAndValue
v-else
:label="$t('main.loadpoint.duration')"
:value="fmtDuration(chargeDurationInterpolated)"
align="end"
/>
</div>
<LoadpointSessionInfo v-bind="sessionInfoProps" />
</div>
<hr class="divider" />
<Vehicle
Expand Down Expand Up @@ -167,7 +108,7 @@ import collector from "../mixins/collector";
import LoadpointSettingsButton from "./LoadpointSettingsButton.vue";
import LoadpointSettingsModal from "./LoadpointSettingsModal.vue";
import VehicleIcon from "./VehicleIcon";
import { getSessionInfo, setSessionInfo, SESSION } from "../sessionInfo";
import LoadpointSessionInfo from "./LoadpointSessionInfo.vue";
export default {
name: "Loadpoint",
Expand All @@ -178,6 +119,7 @@ export default {
LabelAndValue,
LoadpointSettingsButton,
LoadpointSettingsModal,
LoadpointSessionInfo,
VehicleIcon,
},
mixins: [formatter, collector],
Expand Down Expand Up @@ -265,8 +207,6 @@ export default {
guardRemainingInterpolated: this.guardRemaining,
chargeDurationInterpolated: this.chargeDuration,
chargeRemainingDurationInterpolated: this.chargeRemainingDuration,
sessionInfo: getSessionInfo(this.id),
SESSION,
};
},
computed: {
Expand All @@ -279,6 +219,9 @@ export default {
phasesProps: function () {
return this.collectProps(Phases);
},
sessionInfoProps: function () {
return this.collectProps(LoadpointSessionInfo);
},
settingsModal: function () {
return this.collectProps(LoadpointSettingsModal);
},
Expand All @@ -294,17 +237,6 @@ export default {
socBasedCharging: function () {
return (!this.vehicleFeatureOffline && this.vehiclePresent) || this.vehicleSoc > 0;
},
sessionOptions: function () {
const result = [SESSION.TIME, SESSION.SOLAR];
if (this.currency) {
result.push(SESSION.PRICE);
result.push(SESSION.AVG_PRICE);
}
if (this.tariffCo2 > 0 || this.sessionCo2PerKWh > 0) {
result.push(SESSION.CO2);
}
return result;
},
},
watch: {
phaseRemaining() {
Expand Down Expand Up @@ -391,25 +323,6 @@ export default {
const inKw = value == 0 || value >= 1000;
return this.fmtKWh(value, inKw);
},
fmtPrice(value) {
return `${this.fmtMoney(value, this.currency)} ${this.fmtCurrencySymbol(
this.currency
)}`;
},
fmtAvgPrice(value) {
return this.fmtPricePerKWh(value, this.currency, false);
},
fmtAvgPriceShort(value) {
return this.fmtPricePerKWh(value, this.currency, true);
},
fmtSolar(value) {
return `${this.fmtNumber(value, 1)}%`;
},
nextSessionInfo() {
const index = this.sessionOptions.indexOf(this.sessionInfo);
this.sessionInfo = this.sessionOptions[index + 1] || this.sessionOptions[0];
setSessionInfo(this.id, this.sessionInfo);
},
},
};
</script>
Expand Down Expand Up @@ -449,8 +362,4 @@ export default {
margin: 0 -1.5rem;
}
}
.sessionInfo {
cursor: pointer;
user-select: none;
}
</style>
158 changes: 158 additions & 0 deletions assets/js/components/LoadpointSessionInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<template>
<div class="sessionInfo">
<LabelAndValue class="d-block" align="end">
<template #label>
<CustomSelect
:selected="selectedKey"
:options="selectOptions"
data-testid="sessionInfoSelect"
@change="selectOption($event.target.value)"
>
<span class="text-decoration-underline" data-testid="sessionInfoLabel">
{{ label }}
</span>
</CustomSelect>
</template>
<template #value>
<div data-testid="sessionInfoValue" @click="nextSessionInfo">
<div :class="{ 'd-none d-sm-block': showSm }">{{ value }}</div>
<div v-if="showSm" class="d-block d-sm-none">{{ valueSm }}</div>
</div>
</template>
</LabelAndValue>
</div>
</template>

<script>
import LabelAndValue from "./LabelAndValue.vue";
import formatter from "../mixins/formatter";
import CustomSelect from "./CustomSelect.vue";
import { getSessionInfo, setSessionInfo } from "../sessionInfo";
export default {
name: "LoadpointSessionInfo",
components: {
LabelAndValue,
CustomSelect,
},
mixins: [formatter],
props: {
id: Number,
sessionEnergy: Number,
sessionCo2PerKWh: Number,
sessionPricePerKWh: Number,
sessionPrice: Number,
currency: String,
sessionSolarPercentage: Number,
chargeRemainingDurationInterpolated: Number,
chargeDurationInterpolated: Number,
tariffCo2: Number,
tariffGrid: Number,
},
data() {
return {
selectedKey: getSessionInfo(this.id),
};
},
computed: {
options: function () {
const result = [
{
key: "remaining",
value: this.fmtDuration(this.chargeRemainingDurationInterpolated),
available: this.chargeRemainingDurationInterpolated > 0,
},
{
key: "duration",
value: this.fmtDuration(this.chargeDurationInterpolated),
},
{
key: "solar",
value: this.solarFormatted,
},
{
key: "avgPrice",
value: this.fmtAvgPrice(this.sessionPricePerKWh),
valueSm: this.fmtAvgPriceShort(this.sessionPricePerKWh),
available: this.tariffGrid !== undefined,
},
{
key: "price",
value: this.priceFormatted,
available: this.tariffGrid !== undefined,
},
{
key: "co2",
value: this.fmtCo2Medium(this.sessionCo2PerKWh),
valueSm: this.fmtCo2Short(this.sessionCo2PerKWh),
available: this.tariffCo2 !== undefined,
},
];
// only show options that are available
return result.filter(({ available }) => available === undefined || available);
},
optionKeys() {
return this.options.map((option) => option.key);
},
selectOptions() {
return this.optionKeys.map((key) => ({
name: this.$t(`main.loadpoint.${key}`),
value: key,
}));
},
selectedOption() {
return (
this.options.find((option) => option.key === this.selectedKey) || this.options[0]
);
},
label() {
return this.$t(`main.loadpoint.${this.selectedOption.key}`);
},
value() {
return this.selectedOption.value;
},
valueSm() {
return this.selectedOption.valueSm;
},
showSm() {
return this.valueSm !== undefined;
},
solarFormatted() {
return `${this.fmtNumber(this.sessionSolarPercentage, 1)}%`;
},
priceFormatted() {
return `${this.fmtMoney(this.sessionPrice, this.currency)} ${this.fmtCurrencySymbol(
this.currency
)}`;
},
},
methods: {
fmtAvgPrice(value) {
return this.fmtPricePerKWh(value, this.currency, false);
},
fmtAvgPriceShort(value) {
return this.fmtPricePerKWh(value, this.currency, true);
},
nextSessionInfo() {
const index = this.optionKeys.indexOf(this.selectedKey);
this.selectedKey = this.optionKeys[index + 1] || this.optionKeys[0];
this.presist();
},
selectOption(value) {
this.selectedKey = value;
this.presist();
},
presist() {
setSessionInfo(this.id, this.selectedKey);
},
},
};
</script>

<style scoped>
.sessionInfo * {
cursor: pointer;
user-select: none;
-webkit-user-select: none;
}
</style>
4 changes: 2 additions & 2 deletions assets/js/components/Savings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
class="btn btn-link pe-0 text-decoration-none evcc-default-text text-nowrap d-flex align-items-end"
@click="openModal"
>
<span class="d-inline d-sm-none">{{
<span class="d-inline d-sm-none text-decoration-underline">{{
$t("footer.savings.footerShort", { percent })
}}</span
><span class="d-none d-sm-inline">{{
><span class="d-none d-sm-inline text-decoration-underline">{{
$t("footer.savings.footerLong", { percent })
}}</span>
<shopicon-regular-sun class="ms-2 text-evcc"></shopicon-regular-sun>
Expand Down
6 changes: 3 additions & 3 deletions assets/js/components/Version.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class="btn btn-link ps-0 text-decoration-none evcc-default-text text-nowrap d-flex align-items-end"
>
<Logo class="logo me-2" />
v{{ installed }}
<span class="text-decoration-underline">v{{ installed }}</span>
<shopicon-regular-moonstars class="ms-2 text-gray-light"></shopicon-regular-moonstars>
</a>
<button
Expand All @@ -17,7 +17,7 @@
@click="openModal"
>
<shopicon-regular-gift class="me-2"></shopicon-regular-gift>
v{{ installed }}
<span class="text-decoration-underline">v{{ installed }}</span>
<span class="ms-2 d-none d-sm-block text-gray-medium text-decoration-underline">
{{ $t("footer.version.availableLong") }}
</span>
Expand All @@ -29,7 +29,7 @@
class="btn btn-link evcc-default-text ps-0 text-decoration-none text-nowrap d-flex align-items-end"
>
<Logo class="logo me-2" />
v{{ installed }}
<span class="text-decoration-underline">v{{ installed }}</span>
</a>

<Teleport to="body">
Expand Down
Loading

0 comments on commit 5ef8825

Please sign in to comment.