add sodistore pro as a new product
This commit is contained in:
parent
d59027a277
commit
3521da7a1d
|
|
@ -202,6 +202,8 @@ public class Controller : ControllerBase
|
|||
bucketPath = "s3://" + installation.S3BucketId + "-e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa/" + startTimestamp;
|
||||
else if (installation.Product == (int)ProductType.SodistoreGrid)
|
||||
bucketPath = "s3://" + installation.S3BucketId + "-5109c126-e141-43ab-8658-f3c44c838ae8/" + startTimestamp;
|
||||
else if (installation.Product == (int)ProductType.SodistorePro)
|
||||
bucketPath = "s3://" + installation.S3BucketId + "-325c9373-9025-4a8d-bf5a-f9eedf1f155c/" + startTimestamp;
|
||||
else
|
||||
bucketPath = "s3://" + installation.S3BucketId + "-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e/" + startTimestamp;
|
||||
Console.WriteLine("Fetching data for "+startTimestamp);
|
||||
|
|
@ -815,9 +817,10 @@ public class Controller : ControllerBase
|
|||
if (installation is null || !user.HasAccessTo(installation))
|
||||
return Unauthorized();
|
||||
|
||||
// AI diagnostics are scoped to SodistoreHome and SodiStoreMax only
|
||||
// AI diagnostics are scoped to SodistoreHome, SodiStoreMax, and SodistorePro only
|
||||
if (installation.Product != (int)ProductType.SodioHome &&
|
||||
installation.Product != (int)ProductType.SodiStoreMax)
|
||||
installation.Product != (int)ProductType.SodiStoreMax &&
|
||||
installation.Product != (int)ProductType.SodistorePro)
|
||||
return BadRequest("AI diagnostics not available for this product.");
|
||||
|
||||
var result = await DiagnosticService.DiagnoseAsync(installationId, errorDescription, user.Language ?? "en");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ public enum ProductType
|
|||
Salidomo = 1,
|
||||
SodioHome =2,
|
||||
SodiStoreMax=3,
|
||||
SodistoreGrid=4
|
||||
SodistoreGrid=4,
|
||||
SodistorePro=5
|
||||
}
|
||||
|
||||
public enum StatusType
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ public static class ExoCmd
|
|||
String rolename = installation.Product==(int)ProductType.Salimax?Db.Installations.Count(f => f.Product == (int)ProductType.Salimax) + installation.Name:
|
||||
installation.Product==(int)ProductType.SodiStoreMax?Db.Installations.Count(f => f.Product == (int)ProductType.SodiStoreMax) + installation.Name:
|
||||
installation.Product==(int)ProductType.SodistoreGrid?Db.Installations.Count(f => f.Product == (int)ProductType.SodistoreGrid) + installation.Name:
|
||||
installation.Product==(int)ProductType.SodistorePro?Db.Installations.Count(f => f.Product == (int)ProductType.SodistorePro) + installation.Name:
|
||||
Db.Installations.Count(f => f.Product == (int)ProductType.Salidomo) + installation.Name;
|
||||
|
||||
|
||||
|
|
@ -350,6 +351,7 @@ public static class ExoCmd
|
|||
String rolename = installation.Product==(int)ProductType.Salimax?Db.Installations.Count(f => f.Product == (int)ProductType.Salimax) + installation.Name:
|
||||
installation.Product==(int)ProductType.SodiStoreMax?Db.Installations.Count(f => f.Product == (int)ProductType.SodiStoreMax) + installation.Name:
|
||||
installation.Product==(int)ProductType.SodistoreGrid?Db.Installations.Count(f => f.Product == (int)ProductType.SodistoreGrid) + installation.Name:
|
||||
installation.Product==(int)ProductType.SodistorePro?Db.Installations.Count(f => f.Product == (int)ProductType.SodistorePro) + installation.Name:
|
||||
Db.Installations.Count(f => f.Product == (int)ProductType.Salidomo) + installation.Name;
|
||||
|
||||
var contentString = $$"""
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public static class InstallationMethods
|
|||
private static readonly String SalidomoBucketNameSalt = "c0436b6a-d276-4cd8-9c44-1eae86cf5d0e";
|
||||
private static readonly String SodioHomeBucketNameSalt = "e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa";
|
||||
private static readonly String SodistoreGridBucketNameSalt = "5109c126-e141-43ab-8658-f3c44c838ae8";
|
||||
private static readonly String SodistoreProBucketNameSalt = "325c9373-9025-4a8d-bf5a-f9eedf1f155c";
|
||||
|
||||
public static String BucketName(this Installation installation)
|
||||
{
|
||||
|
|
@ -29,6 +30,11 @@ public static class InstallationMethods
|
|||
return $"{installation.S3BucketId}-{SodistoreGridBucketNameSalt}";
|
||||
}
|
||||
|
||||
if (installation.Product == (int)ProductType.SodistorePro)
|
||||
{
|
||||
return $"{installation.S3BucketId}-{SodistoreProBucketNameSalt}";
|
||||
}
|
||||
|
||||
return $"{installation.S3BucketId}-{SalidomoBucketNameSalt}";
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ public static class SessionMethods
|
|||
|
||||
}
|
||||
|
||||
if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodioHome || installation.Product == (int)ProductType.SodistoreGrid)
|
||||
if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodioHome || installation.Product == (int)ProductType.SodistoreGrid || installation.Product == (int)ProductType.SodistorePro)
|
||||
{
|
||||
return user is not null
|
||||
&& user.UserType != 0
|
||||
|
|
@ -295,7 +295,7 @@ public static class SessionMethods
|
|||
.Apply(Db.Update);
|
||||
}
|
||||
|
||||
if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodistoreGrid)
|
||||
if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodistoreGrid || installation.Product == (int)ProductType.SodistorePro)
|
||||
{
|
||||
|
||||
return user is not null
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public class Session : Relation<String, Int64>
|
|||
public Boolean AccessToSodistoreMax { get; set; } = false;
|
||||
public Boolean AccessToSodioHome { get; set; } = false;
|
||||
public Boolean AccessToSodistoreGrid { get; set; } = false;
|
||||
public Boolean AccessToSodistorePro { get; set; } = false;
|
||||
[Ignore] public Boolean Valid => DateTime.Now - LastSeen <=MaxAge ;
|
||||
|
||||
// Private backing field
|
||||
|
|
@ -51,6 +52,7 @@ public class Session : Relation<String, Int64>
|
|||
AccessToSodistoreMax = user.AccessibleInstallations(product: (int)ProductType.SodiStoreMax).ToList().Count > 0;
|
||||
AccessToSodioHome = user.AccessibleInstallations(product: (int)ProductType.SodioHome).ToList().Count > 0;
|
||||
AccessToSodistoreGrid = user.AccessibleInstallations(product: (int)ProductType.SodistoreGrid).ToList().Count > 0;
|
||||
AccessToSodistorePro = user.AccessibleInstallations(product: (int)ProductType.SodistorePro).ToList().Count > 0;
|
||||
|
||||
Console.WriteLine("salimax" +user.AccessibleInstallations(product: (int)ProductType.Salimax).ToList().Count);
|
||||
Console.WriteLine("AccessToSodistoreMax" +user.AccessibleInstallations(product: (int)ProductType.SodiStoreMax).ToList().Count);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public static class DailyIngestionService
|
|||
Console.WriteLine($"[DailyIngestion] Starting ingestion for all SodioHome installations...");
|
||||
|
||||
var installations = Db.Installations
|
||||
.Where(i => i.Product == (Int32)ProductType.SodioHome && i.Device != 3) // Skip Growatt (device=3)
|
||||
.Where(i => (i.Product == (Int32)ProductType.SodioHome || i.Product == (Int32)ProductType.SodistorePro) && i.Device != 3) // Skip Growatt (device=3)
|
||||
.ToList();
|
||||
|
||||
foreach (var installation in installations)
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public static class ReportAggregationService
|
|||
Console.WriteLine("[ReportAggregation] Running Monday weekly report generation...");
|
||||
|
||||
var installations = Db.Installations
|
||||
.Where(i => i.Product == (Int32)ProductType.SodioHome && i.Device != 3) // Skip Growatt (device=3)
|
||||
.Where(i => (i.Product == (Int32)ProductType.SodioHome || i.Product == (Int32)ProductType.SodistorePro) && i.Device != 3) // Skip Growatt (device=3)
|
||||
.ToList();
|
||||
|
||||
var generated = 0;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,11 @@ public static class RabbitMqManager
|
|||
monitorLink =
|
||||
$"https://monitor.inesco.energy/sodistoregrid_installations/list/installation/{installation.S3BucketId}/batteryview";
|
||||
}
|
||||
else if (installation.Product == (int)ProductType.SodistorePro)
|
||||
{
|
||||
monitorLink =
|
||||
$"https://monitor.inesco.energy/sodistorepro_installations/list/installation/{installation.S3BucketId}/batteryview";
|
||||
}
|
||||
else
|
||||
{
|
||||
monitorLink =
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ public static class WebsocketManager
|
|||
(installationConnection.Value.Product == (int)ProductType.Salidomo && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(60)) ||
|
||||
(installationConnection.Value.Product == (int)ProductType.SodioHome && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(4)) ||
|
||||
(installationConnection.Value.Product == (int)ProductType.SodiStoreMax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)) ||
|
||||
(installationConnection.Value.Product == (int)ProductType.SodistoreGrid && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2))
|
||||
(installationConnection.Value.Product == (int)ProductType.SodistoreGrid && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)) ||
|
||||
(installationConnection.Value.Product == (int)ProductType.SodistorePro && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(4))
|
||||
)
|
||||
{
|
||||
Console.WriteLine("Installation ID is " + installationConnection.Key);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ function App() {
|
|||
setAccessToSalidomo,
|
||||
setAccessToSodiohome,
|
||||
setAccessToSodistore,
|
||||
setAccessToSodistoreGrid
|
||||
setAccessToSodistoreGrid,
|
||||
setAccessToSodistorePro
|
||||
} = useContext(ProductIdContext);
|
||||
|
||||
const [language, setLanguage] = useState<string>(
|
||||
|
|
@ -106,6 +107,7 @@ function App() {
|
|||
setAccessToSodiohome(response.data.accessToSodioHome);
|
||||
setAccessToSodistore(response.data.accessToSodistoreMax);
|
||||
setAccessToSodistoreGrid(response.data.accessToSodistoreGrid);
|
||||
setAccessToSodistorePro(response.data.accessToSodistorePro);
|
||||
if (response.data.accessToSalimax) {
|
||||
navigate(routes.installations);
|
||||
} else if (response.data.accessToSalidomo) {
|
||||
|
|
@ -114,6 +116,8 @@ function App() {
|
|||
navigate(routes.sodistore_installations);
|
||||
} else if (response.data.accessToSodistoreGrid) {
|
||||
navigate(routes.sodistoregrid_installations);
|
||||
} else if (response.data.accessToSodistorePro) {
|
||||
navigate(routes.sodistorepro_installations);
|
||||
} else {
|
||||
navigate(routes.sodiohome_installations);
|
||||
}
|
||||
|
|
@ -228,6 +232,15 @@ function App() {
|
|||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path={routes.sodistorepro_installations + '*'}
|
||||
element={
|
||||
<AccessContextProvider>
|
||||
<SodioHomeInstallationTabs product={5} />
|
||||
</AccessContextProvider>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path={routes.sodistoregrid_installations + '*'}
|
||||
element={
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"sodistore_installations": "/sodistore_installations/",
|
||||
"sodiohome_installations": "/sodiohome_installations/",
|
||||
"sodistoregrid_installations": "/sodistoregrid_installations/",
|
||||
"sodistorepro_installations": "/sodistorepro_installations/",
|
||||
"installation": "installation/",
|
||||
"login": "/login/",
|
||||
"forgotPassword": "/forgotPassword/",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ function Login() {
|
|||
setAccessToSalidomo,
|
||||
setAccessToSodiohome,
|
||||
setAccessToSodistore,
|
||||
setAccessToSodistoreGrid
|
||||
setAccessToSodistoreGrid,
|
||||
setAccessToSodistorePro
|
||||
} = useContext(ProductIdContext);
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
|
@ -86,6 +87,7 @@ function Login() {
|
|||
setAccessToSodiohome(response.data.accessToSodioHome);
|
||||
setAccessToSodistore(response.data.accessToSodistoreMax);
|
||||
setAccessToSodistoreGrid(response.data.accessToSodistoreGrid);
|
||||
setAccessToSodistorePro(response.data.accessToSodistorePro);
|
||||
if (response.data.accessToSalimax) {
|
||||
navigate(routes.installations);
|
||||
} else if (response.data.accessToSalidomo) {
|
||||
|
|
@ -94,6 +96,8 @@ function Login() {
|
|||
navigate(routes.sodistore_installations);
|
||||
} else if (response.data.accessToSodistoreGrid) {
|
||||
navigate(routes.sodistoregrid_installations);
|
||||
} else if (response.data.accessToSodistorePro) {
|
||||
navigate(routes.sodistorepro_installations);
|
||||
} else {
|
||||
navigate(routes.sodiohome_installations);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import {
|
|||
computeFlatValues,
|
||||
wouldLoseData,
|
||||
SODIOHOME_DEVICE_TYPES,
|
||||
buildSodistoreProPreset,
|
||||
} from './installationSetupUtils';
|
||||
|
||||
interface InformationSodistorehomeProps {
|
||||
|
|
@ -94,13 +95,25 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
return [value.trim()];
|
||||
};
|
||||
|
||||
const DeviceTypes = SODIOHOME_DEVICE_TYPES;
|
||||
const isSodistorePro = props.values.product === 5;
|
||||
const DeviceTypes = isSodistorePro
|
||||
? [{ id: 4, name: 'inesco 12K - WR Hybrid' } as const]
|
||||
: SODIOHOME_DEVICE_TYPES;
|
||||
|
||||
// Preset state — initializes from persisted installationModel, empty for legacy
|
||||
const [selectedPreset, setSelectedPreset] = useState<string>(
|
||||
props.values.installationModel || ''
|
||||
);
|
||||
const presetConfig: PresetConfig | null = INSTALLATION_PRESETS[selectedPreset] || null;
|
||||
const [inverterCount, setInverterCount] = useState<string>(
|
||||
isSodistorePro && props.values.installationModel
|
||||
? props.values.installationModel
|
||||
: ''
|
||||
);
|
||||
const presetConfig: PresetConfig | null = isSodistorePro
|
||||
? (inverterCount && parseInt(inverterCount, 10) > 0
|
||||
? buildSodistoreProPreset(parseInt(inverterCount, 10))
|
||||
: null)
|
||||
: (INSTALLATION_PRESETS[selectedPreset] || null);
|
||||
|
||||
const [batterySnTree, setBatterySnTree] = useState<BatterySnTree>(() => {
|
||||
if (presetConfig) {
|
||||
|
|
@ -200,6 +213,38 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
});
|
||||
};
|
||||
|
||||
const handleInverterCountChange = (value: string) => {
|
||||
if (value !== '' && !/^\d+$/.test(value)) return;
|
||||
if (value !== '' && parseInt(value, 10) > 20) return;
|
||||
setInverterCount(value);
|
||||
const count = parseInt(value, 10);
|
||||
if (isNaN(count) || count < 1) {
|
||||
setBatterySnTree([]);
|
||||
setFormValues({ ...formValues, installationModel: value });
|
||||
return;
|
||||
}
|
||||
const newConfig = buildSodistoreProPreset(count);
|
||||
const newTree = batterySnTree.length > 0
|
||||
? remapTree(batterySnTree, newConfig)
|
||||
: buildEmptyTree(newConfig);
|
||||
setBatterySnTree(newTree);
|
||||
const newInvSNs = Array.from({ length: count }, (_, i) => inverterSerialNumbers[i] || '');
|
||||
const newDlSNs = Array.from({ length: count }, (_, i) => dataloggerSerialNumbers[i] || '');
|
||||
const newPvStrings = Array.from({ length: count }, (_, i) => pvStringsPerInverter[i] || '1');
|
||||
setInverterSerialNumbers(newInvSNs);
|
||||
setDataloggerSerialNumbers(newDlSNs);
|
||||
setPvStringsPerInverter(newPvStrings);
|
||||
const flat = computeFlatValues(newConfig, newTree);
|
||||
setFormValues({
|
||||
...formValues,
|
||||
...flat,
|
||||
installationModel: value,
|
||||
inverterSN: newInvSNs.join('/'),
|
||||
dataloggerSN: newDlSNs.join('/'),
|
||||
pvStringsPerInverter: newPvStrings.join(','),
|
||||
});
|
||||
};
|
||||
|
||||
const handleInverterSnChange = (invIdx: number, value: string) => {
|
||||
const updated = [...inverterSerialNumbers];
|
||||
updated[invIdx] = value;
|
||||
|
|
@ -608,6 +653,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{!isSodistorePro && (
|
||||
<div>
|
||||
<FormControl fullWidth sx={{ marginLeft: 1, marginTop: 1, marginBottom: 1, width: 440 }}>
|
||||
<InputLabel sx={{ fontSize: 14, backgroundColor: 'white' }}>
|
||||
|
|
@ -627,6 +673,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Autocomplete
|
||||
|
|
@ -733,6 +780,19 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
/>
|
||||
</div>
|
||||
|
||||
{isSodistorePro ? (
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="numberOfInverters" defaultMessage="Number of Inverters" />}
|
||||
type="text"
|
||||
value={inverterCount}
|
||||
onChange={(e) => handleInverterCountChange(e.target.value)}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<FormControl sx={{ m: 1, width: '50ch' }}>
|
||||
<InputLabel
|
||||
|
|
@ -759,6 +819,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
|
|
@ -919,7 +980,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
<div>
|
||||
<TextField
|
||||
label="S3 Bucket Name"
|
||||
value={formValues.s3BucketId + '-e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa'}
|
||||
value={formValues.s3BucketId + '-' + (isSodistorePro ? '325c9373-9025-4a8d-bf5a-f9eedf1f155c' : 'e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa')}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@ export const INSTALLATION_PRESETS: Record<string, PresetConfig> = {
|
|||
'sodistore home 36': [[2, 2], [2, 2]],
|
||||
};
|
||||
|
||||
export const buildSodistoreProPreset = (inverterCount: number): PresetConfig =>
|
||||
Array.from({ length: inverterCount }, () => [2, 2]);
|
||||
|
||||
export const parseSodistoreProInverterCount = (model: string): number => {
|
||||
const n = parseInt(model, 10);
|
||||
return isNaN(n) || n < 1 ? 1 : n;
|
||||
};
|
||||
|
||||
export const buildEmptyTree = (preset: PresetConfig): BatterySnTree => {
|
||||
return preset.map((inv) =>
|
||||
inv.map((batteryCount) => Array.from({ length: batteryCount }, () => ''))
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export const fetchAggregatedDataJson = (
|
|||
} else if (r.status === 200) {
|
||||
const jsontext = await r.text();
|
||||
|
||||
if (product === 2) {
|
||||
if (product === 2 || product === 5) {
|
||||
return parseSinexcelAggregatedData(jsontext);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,13 +107,15 @@ function UserAccess(props: UserAccessProps) {
|
|||
|
||||
const fetchAvailableInstallations = useCallback(async () => {
|
||||
try {
|
||||
const [res0, res1, res2, res3] = await Promise.all([
|
||||
const [res0, res1, res2, res3, res4, res5] = await Promise.all([
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=0`),
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=1`),
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=2`),
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=3`)
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=3`),
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=4`),
|
||||
axiosConfig.get(`/GetAllInstallationsFromProduct?product=5`)
|
||||
]);
|
||||
setAvailableInstallations([...res0.data, ...res1.data, ...res2.data, ...res3.data]);
|
||||
setAvailableInstallations([...res0.data, ...res1.data, ...res2.data, ...res3.data, ...res4.data, ...res5.data]);
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 401) removeToken();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -817,7 +817,7 @@ function Overview(props: OverviewProps) {
|
|||
type: 'bar',
|
||||
color: '#ff9900'
|
||||
},
|
||||
...(product !== 2 ? [{
|
||||
...((product !== 2 && product !== 5) ? [{
|
||||
name: 'Net Energy',
|
||||
color: '#e65100',
|
||||
type: 'line',
|
||||
|
|
@ -840,7 +840,7 @@ function Overview(props: OverviewProps) {
|
|||
alignItems="stretch"
|
||||
spacing={3}
|
||||
>
|
||||
{!(aggregatedData && product === 2) && (
|
||||
{!(aggregatedData && (product === 2 || product === 5)) && (
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
|
|
@ -933,7 +933,7 @@ function Overview(props: OverviewProps) {
|
|||
</Card>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item md={(aggregatedData && product === 2) ? 12 : 6} xs={12}>
|
||||
<Grid item md={(aggregatedData && (product === 2 || product === 5)) ? 12 : 6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
overflow: 'visible',
|
||||
|
|
@ -1001,14 +1001,14 @@ function Overview(props: OverviewProps) {
|
|||
<ReactApexChart
|
||||
options={{
|
||||
...getChartOptions(
|
||||
product === 2
|
||||
(product === 2 || product === 5)
|
||||
? aggregatedDataArray[aggregatedChartState]
|
||||
.chartOverview.dcPowerWithoutHeating
|
||||
: aggregatedDataArray[aggregatedChartState]
|
||||
.chartOverview.dcPower,
|
||||
'weekly',
|
||||
aggregatedDataArray[aggregatedChartState].datelist,
|
||||
product === 2
|
||||
(product === 2 || product === 5)
|
||||
)
|
||||
}}
|
||||
series={[
|
||||
|
|
@ -1017,7 +1017,7 @@ function Overview(props: OverviewProps) {
|
|||
.chartData.dcChargingPower,
|
||||
color: '#008FFB'
|
||||
},
|
||||
...(product !== 2 ? [{
|
||||
...((product !== 2 && product !== 5) ? [{
|
||||
...aggregatedDataArray[aggregatedChartState]
|
||||
.chartData.heatingPower,
|
||||
color: '#ff9900'
|
||||
|
|
@ -1073,7 +1073,7 @@ function Overview(props: OverviewProps) {
|
|||
alignItems="stretch"
|
||||
spacing={3}
|
||||
>
|
||||
{product !== 2 && (
|
||||
{(product !== 2 && product !== 5) && (
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
|
|
@ -1136,7 +1136,7 @@ function Overview(props: OverviewProps) {
|
|||
</Card>
|
||||
</Grid>
|
||||
)}
|
||||
{product !== 2 && (
|
||||
{(product !== 2 && product !== 5) && (
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
|
|
@ -1392,7 +1392,7 @@ function Overview(props: OverviewProps) {
|
|||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{aggregatedData && product === 2 && (
|
||||
{aggregatedData && (product === 2 || product === 5) && (
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
|
|
@ -1457,7 +1457,7 @@ function Overview(props: OverviewProps) {
|
|||
alignItems="stretch"
|
||||
spacing={3}
|
||||
>
|
||||
<Grid item md={product === 2 ? 12 : 6} xs={12}>
|
||||
<Grid item md={(product === 2 || product === 5) ? 12 : 6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
overflow: 'visible',
|
||||
|
|
@ -1518,7 +1518,7 @@ function Overview(props: OverviewProps) {
|
|||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
{product !== 2 && (
|
||||
{(product !== 2 && product !== 5) && (
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ import { getDeviceTypeName } from '../Information/installationSetupUtils';
|
|||
|
||||
interface FlatInstallationViewProps {
|
||||
installations: I_Installation[];
|
||||
product?: number;
|
||||
}
|
||||
|
||||
const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||
const navigate = useNavigate();
|
||||
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
||||
const currentLocation = useLocation();
|
||||
const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations;
|
||||
//
|
||||
const sortedInstallations = [...props.installations].sort((a, b) => {
|
||||
// Compare the status field of each installation and sort them based on the status.
|
||||
|
|
@ -51,7 +53,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
setSelectedInstallation(-1);
|
||||
|
||||
navigate(
|
||||
routes.sodiohome_installations +
|
||||
baseRoute +
|
||||
routes.list +
|
||||
routes.installation +
|
||||
`${installationID}` +
|
||||
|
|
@ -82,9 +84,9 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
sx={{
|
||||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.sodiohome_installations + 'list' ||
|
||||
baseRoute + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodiohome_installations + routes.list
|
||||
baseRoute + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,9 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
|||
const s3Bucket =
|
||||
props.current_installation.s3BucketId.toString() +
|
||||
'-' +
|
||||
'e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa';
|
||||
(props.current_installation.product === 5
|
||||
? '325c9373-9025-4a8d-bf5a-f9eedf1f155c'
|
||||
: 'e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa');
|
||||
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser } = context;
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@ import SodioHomeInstallation from './Installation';
|
|||
|
||||
interface installationSearchProps {
|
||||
installations: I_Installation[];
|
||||
product?: number;
|
||||
}
|
||||
|
||||
function InstallationSearch(props: installationSearchProps) {
|
||||
const intl = useIntl();
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const currentLocation = useLocation();
|
||||
const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations;
|
||||
// const [filteredData, setFilteredData] = useState(props.installations);
|
||||
|
||||
const indexedData = useMemo(() => {
|
||||
|
|
@ -46,9 +48,9 @@ function InstallationSearch(props: installationSearchProps) {
|
|||
sx={{
|
||||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.sodiohome_installations + 'list' ||
|
||||
baseRoute + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodiohome_installations + routes.list
|
||||
baseRoute + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
|
|
@ -79,7 +81,7 @@ function InstallationSearch(props: installationSearchProps) {
|
|||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<FlatInstallationView installations={filteredData} />
|
||||
<FlatInstallationView installations={filteredData} product={props.product} />
|
||||
<Routes>
|
||||
{filteredData.map((installation) => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -23,20 +23,26 @@ interface SodistorehomeInstallationFormPros {
|
|||
cancel: () => void;
|
||||
submit: () => void;
|
||||
parentid: number;
|
||||
product?: number;
|
||||
}
|
||||
|
||||
function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros) {
|
||||
const theme = useTheme();
|
||||
const [open, setOpen] = useState(true);
|
||||
const isSodistorePro = props.product === 5;
|
||||
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
|
||||
name: '',
|
||||
vpnIp: '',
|
||||
installationModel: '',
|
||||
externalEms: 'No',
|
||||
...(isSodistorePro ? { device: 4 } : {}),
|
||||
});
|
||||
const requiredFields = ['name', 'vpnIp', 'installationModel'];
|
||||
const [inverterCount, setInverterCount] = useState('');
|
||||
const requiredFields = ['name', 'vpnIp', ...(isSodistorePro ? [] : ['installationModel'])];
|
||||
|
||||
const DeviceTypes = SODIOHOME_DEVICE_TYPES;
|
||||
const DeviceTypes = isSodistorePro
|
||||
? [{ id: 4, name: 'inesco 12K - WR Hybrid' }]
|
||||
: SODIOHOME_DEVICE_TYPES;
|
||||
const installationContext = useContext(InstallationsContext);
|
||||
const { createInstallation, loading, setLoading, error, setError } =
|
||||
installationContext;
|
||||
|
|
@ -52,7 +58,10 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
const handleSubmit = async (e) => {
|
||||
setLoading(true);
|
||||
formValues.parentId = props.parentid;
|
||||
formValues.product = 2;
|
||||
formValues.product = props.product ?? 2;
|
||||
if (isSodistorePro) {
|
||||
formValues.installationModel = inverterCount;
|
||||
}
|
||||
const responseData = await createInstallation(formValues);
|
||||
props.submit();
|
||||
};
|
||||
|
|
@ -66,6 +75,9 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (isSodistorePro && (!inverterCount || parseInt(inverterCount, 10) < 1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -132,6 +144,29 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
/>
|
||||
</div>
|
||||
|
||||
{isSodistorePro ? (
|
||||
<div>
|
||||
<TextField
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="numberOfInverters"
|
||||
defaultMessage="Number of Inverters"
|
||||
/>
|
||||
}
|
||||
name="inverterCount"
|
||||
type="text"
|
||||
value={inverterCount}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val === '' || (/^\d+$/.test(val) && parseInt(val, 10) <= 20)) {
|
||||
setInverterCount(val);
|
||||
}
|
||||
}}
|
||||
required
|
||||
error={!inverterCount || parseInt(inverterCount, 10) < 1}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<FormControl
|
||||
fullWidth
|
||||
|
|
@ -167,7 +202,9 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isSodistorePro && (
|
||||
<div>
|
||||
<FormControl
|
||||
fullWidth
|
||||
|
|
@ -201,6 +238,7 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</Box>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
|
|||
closeSocket
|
||||
} = useContext(InstallationsContext);
|
||||
const { product, setProduct } = useContext(ProductIdContext);
|
||||
const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations;
|
||||
|
||||
useEffect(() => {
|
||||
let path = location.pathname.split('/');
|
||||
|
|
@ -484,6 +485,7 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
|
|||
<Box p={4}>
|
||||
<InstallationSearch
|
||||
installations={sodiohomeInstallations}
|
||||
product={props.product}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
|
@ -496,7 +498,7 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
|
|||
path={'*'}
|
||||
element={
|
||||
<Navigate
|
||||
to={routes.sodiohome_installations + routes.list}
|
||||
to={baseRoute + routes.list}
|
||||
></Navigate>
|
||||
}
|
||||
></Route>
|
||||
|
|
|
|||
|
|
@ -742,7 +742,8 @@ function TicketDetailPage() {
|
|||
1: routes.salidomo_installations,
|
||||
2: routes.sodiohome_installations,
|
||||
3: routes.sodistore_installations,
|
||||
4: routes.sodistoregrid_installations
|
||||
4: routes.sodistoregrid_installations,
|
||||
5: routes.sodistorepro_installations
|
||||
};
|
||||
const prefix = productRoutes[detail.installationProduct] ?? routes.installations;
|
||||
navigate(
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
|||
? routes.salidomo_installations
|
||||
: installation.product == 2
|
||||
? routes.sodiohome_installations
|
||||
: installation.product == 5
|
||||
? routes.sodistorepro_installations
|
||||
: routes.sodistore_installations;
|
||||
|
||||
let folder_path =
|
||||
|
|
@ -69,6 +71,8 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
|||
? routes.salidomo_installations
|
||||
: product == 2
|
||||
? routes.sodiohome_installations
|
||||
: product == 5
|
||||
? routes.sodistorepro_installations
|
||||
: routes.sodistore_installations;
|
||||
|
||||
if (installation.type != 'Folder') {
|
||||
|
|
|
|||
|
|
@ -65,11 +65,12 @@ function TreeInformation(props: TreeInformationProps) {
|
|||
setProduct(e.target.value); // Directly update the product state
|
||||
};
|
||||
|
||||
const ProductTypes = ['Salimax', 'Salidomo', 'SodistoreHome', 'SodistoreMax', 'SodistoreGrid'];
|
||||
const ProductTypes = ['Salimax', 'Salidomo', 'SodistoreHome', 'SodistoreMax', 'SodistoreGrid', 'SodistorePro'];
|
||||
const ProductDisplayNames: Record<string, string> = {
|
||||
'SodistoreHome': 'Sodistore Home',
|
||||
'SodistoreMax': 'Sodistore Max',
|
||||
'SodistoreGrid': 'Sodistore Grid'
|
||||
'SodistoreGrid': 'Sodistore Grid',
|
||||
'SodistorePro': 'Sodistore Pro'
|
||||
};
|
||||
|
||||
const isMobile = window.innerWidth <= 1490;
|
||||
|
|
@ -345,11 +346,12 @@ function TreeInformation(props: TreeInformationProps) {
|
|||
/>
|
||||
)}
|
||||
|
||||
{openModalInstallation && product == 'SodistoreHome' && (
|
||||
{openModalInstallation && (product == 'SodistoreHome' || product == 'SodistorePro') && (
|
||||
<SodiostorehomeInstallationForm
|
||||
cancel={handleFormCancel}
|
||||
submit={handleInstallationFormSubmit}
|
||||
parentid={props.folder.id}
|
||||
product={product == 'SodistorePro' ? 5 : undefined}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ const InstallationsContextProvider = ({
|
|||
`/GetAllInstallationsFromProduct?product=${product}`
|
||||
);
|
||||
|
||||
if (product === 2) {
|
||||
if (product === 2 || product === 5) {
|
||||
setSodiohomeInstallations(res.data);
|
||||
} else if (product === 1) {
|
||||
setSalidomoInstallations(res.data);
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ interface ProductIdContextType {
|
|||
accessToSodiohome: boolean;
|
||||
accessToSodistore: boolean;
|
||||
accessToSodistoreGrid: boolean;
|
||||
accessToSodistorePro: boolean;
|
||||
setAccessToSalimax: (access: boolean) => void;
|
||||
setAccessToSalidomo: (access: boolean) => void;
|
||||
setAccessToSodiohome: (access: boolean) => void;
|
||||
setAccessToSodistore: (access: boolean) => void;
|
||||
setAccessToSodistoreGrid: (access: boolean) => void;
|
||||
setAccessToSodistorePro: (access: boolean) => void;
|
||||
}
|
||||
|
||||
// Create the context.
|
||||
|
|
@ -49,6 +51,10 @@ export const ProductIdContextProvider = ({
|
|||
const storedValue = localStorage.getItem('accessToSodistoreGrid');
|
||||
return storedValue === 'true';
|
||||
});
|
||||
const [accessToSodistorePro, setAccessToSodistorePro] = useState(() => {
|
||||
const storedValue = localStorage.getItem('accessToSodistorePro');
|
||||
return storedValue === 'true';
|
||||
});
|
||||
// const [product, setProduct] = useState(location.includes('salidomo') ? 1 : 0);
|
||||
// const [product, setProduct] = useState<number>(
|
||||
// productMapping[Object.keys(productMapping).find((key) => location.includes(key)) || ''] || -1
|
||||
|
|
@ -56,6 +62,8 @@ export const ProductIdContextProvider = ({
|
|||
const [product, setProduct] = useState<number>(() => {
|
||||
if (location.includes('salidomo')) {
|
||||
return 1;
|
||||
} else if (location.includes('sodistorepro')) {
|
||||
return 5;
|
||||
} else if (location.includes('sodiohome')) {
|
||||
return 2;
|
||||
} else if (location.includes('sodistoregrid')) {
|
||||
|
|
@ -92,6 +100,10 @@ export const ProductIdContextProvider = ({
|
|||
setAccessToSodistoreGrid(access);
|
||||
localStorage.setItem('accessToSodistoreGrid', JSON.stringify(access));
|
||||
};
|
||||
const changeAccessSodistorePro = (access: boolean) => {
|
||||
setAccessToSodistorePro(access);
|
||||
localStorage.setItem('accessToSodistorePro', JSON.stringify(access));
|
||||
};
|
||||
|
||||
return (
|
||||
<ProductIdContext.Provider
|
||||
|
|
@ -103,11 +115,13 @@ export const ProductIdContextProvider = ({
|
|||
accessToSodiohome,
|
||||
accessToSodistore,
|
||||
accessToSodistoreGrid,
|
||||
accessToSodistorePro,
|
||||
setAccessToSalimax: changeAccessSalimax,
|
||||
setAccessToSalidomo: changeAccessSalidomo,
|
||||
setAccessToSodiohome: changeAccessSodiohome,
|
||||
setAccessToSodistore: changeAccessSodistore,
|
||||
setAccessToSodistoreGrid: changeAccessSodistoreGrid
|
||||
setAccessToSodistoreGrid: changeAccessSodistoreGrid,
|
||||
setAccessToSodistorePro: changeAccessSodistorePro
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ export const transformInputToBatteryViewDataJson = async (
|
|||
}> => {
|
||||
const prefixes = ['', 'k', 'M', 'G', 'T'];
|
||||
const MAX_NUMBER = 9999999;
|
||||
const isSodioHome = product === 2;
|
||||
const isSodioHome = product === 2 || product === 5;
|
||||
const categories = isSodioHome
|
||||
? ['Soc', 'Power', 'Voltage', 'Current', 'Soh']
|
||||
: ['Soc', 'Temperature', 'Power', 'Voltage', 'Current'];
|
||||
|
|
@ -169,7 +169,7 @@ export const transformInputToBatteryViewDataJson = async (
|
|||
);
|
||||
|
||||
const adjustedTimestamp =
|
||||
product == 0 || product == 2 || product == 3 || product == 4
|
||||
product == 0 || product == 2 || product == 3 || product == 4 || product == 5
|
||||
? new Date(timestampArray[i] * 1000)
|
||||
: new Date(timestampArray[i] * 100000);
|
||||
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
|
||||
|
|
@ -393,7 +393,7 @@ export const transformInputToDailyDataJson = async (
|
|||
// custom fallback logic to handle differences between Growatt and Sinexcel.
|
||||
// Growatt has: Battery1AmbientTemperature, GridPower, PvPower
|
||||
// Sinexcel has: Battery1Temperature, TotalGridPower (meter may be offline), PvPower1-4
|
||||
const pathsToSearch = product == 2
|
||||
const pathsToSearch = (product == 2 || product == 5)
|
||||
? [
|
||||
'SODIOHOME_SOC',
|
||||
'SODIOHOME_TEMPERATURE',
|
||||
|
|
@ -516,8 +516,8 @@ export const transformInputToDailyDataJson = async (
|
|||
|
||||
let value: number | undefined = undefined;
|
||||
|
||||
if (product === 2) {
|
||||
// SodioHome: use top-level aggregated values (Sinexcel multi-inverter)
|
||||
if (product === 2 || product === 5) {
|
||||
// SodioHome/SodistorePro: use top-level aggregated values (Sinexcel multi-inverter)
|
||||
const inv = result?.InverterRecord;
|
||||
if (inv) {
|
||||
switch (category_index) {
|
||||
|
|
@ -735,7 +735,7 @@ export const transformInputToAggregatedDataJson = async (
|
|||
const timestampPromises = [];
|
||||
|
||||
while (currentDay.isBefore(end_date)) {
|
||||
const dateFormat = product === 2
|
||||
const dateFormat = (product === 2 || product === 5)
|
||||
? currentDay.format('DDMMYYYY')
|
||||
: currentDay.format('YYYY-MM-DD');
|
||||
timestampPromises.push(
|
||||
|
|
|
|||
|
|
@ -648,5 +648,7 @@
|
|||
"terms_cookies_body": "Browser-Speicher wird für Anmeldesitzungen und Benutzereinstellungen verwendet. Dies ist für die korrekte Funktion der Plattform erforderlich.",
|
||||
"terms_usage_heading": "Nutzungsbedingungen",
|
||||
"terms_usage_body": "Durch die Nutzung dieser Plattform erkennen Sie die allgemeinen Nutzungsbedingungen von inesco Energy an. Bei Fragen wenden Sie sich bitte an Ihren Systemadministrator.",
|
||||
"terms_acknowledge_button": "Ich verstehe"
|
||||
"terms_acknowledge_button": "Ich verstehe",
|
||||
"sodistorepro": "Sodistore Pro",
|
||||
"numberOfInverters": "Anzahl der Wechselrichter"
|
||||
}
|
||||
|
|
@ -396,5 +396,7 @@
|
|||
"terms_cookies_body": "Browser storage is used for login sessions and user preferences. This is required for the platform to function correctly.",
|
||||
"terms_usage_heading": "Terms of Use",
|
||||
"terms_usage_body": "By using this platform, you acknowledge the general terms of use of inesco Energy. For questions, please contact your system administrator.",
|
||||
"terms_acknowledge_button": "I understand"
|
||||
"terms_acknowledge_button": "I understand",
|
||||
"sodistorepro": "Sodistore Pro",
|
||||
"numberOfInverters": "Number of Inverters"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -648,5 +648,7 @@
|
|||
"terms_cookies_body": "Le stockage du navigateur est utilisé pour les sessions de connexion et les préférences utilisateur. Ceci est nécessaire au bon fonctionnement de la plateforme.",
|
||||
"terms_usage_heading": "Conditions d'utilisation",
|
||||
"terms_usage_body": "En utilisant cette plateforme, vous reconnaissez les conditions générales d'utilisation d'inesco Energy. Pour toute question, veuillez contacter votre administrateur système.",
|
||||
"terms_acknowledge_button": "Je comprends"
|
||||
"terms_acknowledge_button": "Je comprends",
|
||||
"sodistorepro": "Sodistore Pro",
|
||||
"numberOfInverters": "Nombre d'onduleurs"
|
||||
}
|
||||
|
|
@ -648,5 +648,7 @@
|
|||
"terms_cookies_body": "L'archiviazione del browser viene utilizzata per le sessioni di accesso e le preferenze utente. Questo è necessario per il corretto funzionamento della piattaforma.",
|
||||
"terms_usage_heading": "Condizioni d'uso",
|
||||
"terms_usage_body": "Utilizzando questa piattaforma, si riconoscono le condizioni generali d'uso di inesco Energy. Per domande, contattare l'amministratore di sistema.",
|
||||
"terms_acknowledge_button": "Ho capito"
|
||||
"terms_acknowledge_button": "Ho capito",
|
||||
"sodistorepro": "Sodistore Pro",
|
||||
"numberOfInverters": "Numero di inverter"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ function SidebarMenu() {
|
|||
accessToSodistore,
|
||||
accessToSalidomo,
|
||||
accessToSodiohome,
|
||||
accessToSodistoreGrid
|
||||
accessToSodistoreGrid,
|
||||
accessToSodistorePro
|
||||
} = useContext(ProductIdContext);
|
||||
|
||||
return (
|
||||
|
|
@ -285,6 +286,27 @@ function SidebarMenu() {
|
|||
</ListItem>
|
||||
</List>
|
||||
)}
|
||||
|
||||
{accessToSodistorePro && (
|
||||
<List component="div">
|
||||
<ListItem component="div">
|
||||
<Button
|
||||
disableRipple
|
||||
component={RouterLink}
|
||||
onClick={closeSidebar}
|
||||
to="/sodistorepro_installations"
|
||||
startIcon={<BrightnessLowTwoToneIcon />}
|
||||
>
|
||||
<Box sx={{ marginTop: '3px' }}>
|
||||
<FormattedMessage
|
||||
id="sodistorepro"
|
||||
defaultMessage="Sodistore Pro"
|
||||
/>
|
||||
</Box>
|
||||
</Button>
|
||||
</ListItem>
|
||||
</List>
|
||||
)}
|
||||
</SubMenuWrapper>
|
||||
</List>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue