grant ready-only Information, Battery , PV, Log and Report to Partner role in Sodistore Home and Report to Customer role

This commit is contained in:
Yinyin Liu 2026-02-26 14:52:29 +01:00
parent d464c9cd71
commit 075624717d
3 changed files with 293 additions and 172 deletions

View File

@ -175,6 +175,9 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
return true; return true;
}; };
const canEdit = currentUser.userType === UserType.admin;
const isPartner = currentUser.userType === UserType.partner;
return ( return (
<> <>
{openModalDeleteInstallation && ( {openModalDeleteInstallation && (
@ -276,6 +279,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
onChange={handleChange} onChange={handleChange}
variant="outlined" variant="outlined"
fullWidth fullWidth
inputProps={{ readOnly: !canEdit }}
/> />
</div> </div>
<div> <div>
@ -288,8 +292,9 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
onChange={handleChange} onChange={handleChange}
variant="outlined" variant="outlined"
fullWidth fullWidth
required required={canEdit}
error={formValues.region === ''} error={canEdit && formValues.region === ''}
inputProps={{ readOnly: !canEdit }}
/> />
</div> </div>
<div> <div>
@ -305,8 +310,9 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
onChange={handleChange} onChange={handleChange}
variant="outlined" variant="outlined"
fullWidth fullWidth
required required={canEdit}
error={formValues.location === ''} error={canEdit && formValues.location === ''}
inputProps={{ readOnly: !canEdit }}
/> />
</div> </div>
<div> <div>
@ -319,23 +325,26 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
onChange={handleChange} onChange={handleChange}
variant="outlined" variant="outlined"
fullWidth fullWidth
required required={canEdit}
error={formValues.country === ''} error={canEdit && formValues.country === ''}
inputProps={{ readOnly: !canEdit }}
/> />
</div> </div>
<div> {canEdit && (
<TextField <div>
label={ <TextField
<FormattedMessage id="vpnip" defaultMessage="VPN IP" /> label={
} <FormattedMessage id="vpnip" defaultMessage="VPN IP" />
name="vpnIp" }
value={formValues.vpnIp} name="vpnIp"
onChange={handleChange} value={formValues.vpnIp}
variant="outlined" onChange={handleChange}
fullWidth variant="outlined"
/> fullWidth
</div> />
</div>
)}
<div> <div>
<FormControl <FormControl
@ -362,6 +371,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
name="device" name="device"
value={formValues.device} value={formValues.device}
onChange={handleChange} onChange={handleChange}
inputProps={{ readOnly: !canEdit }}
> >
{DeviceTypes.map((device) => ( {DeviceTypes.map((device) => (
<MenuItem key={device.id} value={device.id}> <MenuItem key={device.id} value={device.id}>
@ -372,106 +382,116 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
</FormControl> </FormControl>
</div> </div>
<div> {(canEdit || isPartner) && (
<TextField <>
label={ <div>
<FormattedMessage
id="installationSerialNumber"
defaultMessage="Installation Serial Number"
/>
}
name="serialNumber"
value={formValues.serialNumber}
onChange={handleChange}
variant="outlined"
fullWidth
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="inverterSN"
defaultMessage="Inverter Serial Number"
/>
}
name="inverterSN"
value={formValues.inverterSN}
onChange={handleChange}
variant="outlined"
fullWidth
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="dataloggerSN"
defaultMessage="Datalogger Serial Number"
/>
}
name="dataloggerSN"
value={formValues.dataloggerSN}
onChange={handleChange}
variant="outlined"
fullWidth
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="batteryClusterNumber"
defaultMessage="Battery Cluster Number"
/>
}
name="batteryClusterNumber"
value={formValues.batteryClusterNumber}
onChange={handleChange}
variant="outlined"
fullWidth
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="batteryNumber"
defaultMessage="Battery Number"
/>
}
name="batteryNumber"
type="text"
value={batteryNumber === 0 ? '' : batteryNumber}
onChange={handleBatteryNumberChange}
variant="outlined"
fullWidth
placeholder="Enter number of batteries"
/>
</div>
{batteryNumber > 0 &&
batterySerialNumbers.map((serialNumber, index) => (
<div key={index}>
<TextField <TextField
label={`Battery Pack ${index + 1}`} label={
name={`batterySN${index + 1}`} <FormattedMessage
value={serialNumber} id="installationSerialNumber"
onChange={(e) => defaultMessage="Installation Serial Number"
handleBatterySerialNumberChange(index, e.target.value) />
} }
onKeyDown={(e) => handleBatterySnKeyDown(e, index)} name="serialNumber"
inputRef={(el) => (batterySnRefs.current[index] = el)} value={formValues.serialNumber}
onChange={handleChange}
variant="outlined" variant="outlined"
fullWidth fullWidth
placeholder="Scan or enter serial number" inputProps={{ readOnly: !canEdit }}
/> />
</div> </div>
))}
<div>
<TextField
label={
<FormattedMessage
id="inverterSN"
defaultMessage="Inverter Serial Number"
/>
}
name="inverterSN"
value={formValues.inverterSN}
onChange={handleChange}
variant="outlined"
fullWidth
inputProps={{ readOnly: !canEdit }}
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="dataloggerSN"
defaultMessage="Datalogger Serial Number"
/>
}
name="dataloggerSN"
value={formValues.dataloggerSN}
onChange={handleChange}
variant="outlined"
fullWidth
inputProps={{ readOnly: !canEdit }}
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="batteryClusterNumber"
defaultMessage="Battery Cluster Number"
/>
}
name="batteryClusterNumber"
value={formValues.batteryClusterNumber}
onChange={handleChange}
variant="outlined"
fullWidth
inputProps={{ readOnly: !canEdit }}
/>
</div>
<div>
<TextField
label={
<FormattedMessage
id="batteryNumber"
defaultMessage="Battery Number"
/>
}
name="batteryNumber"
type="text"
value={batteryNumber === 0 ? '' : batteryNumber}
onChange={handleBatteryNumberChange}
variant="outlined"
fullWidth
placeholder={canEdit ? 'Enter number of batteries' : ''}
inputProps={{ readOnly: !canEdit }}
/>
</div>
{batteryNumber > 0 &&
batterySerialNumbers.map((serialNumber, index) => (
<div key={index}>
<TextField
label={`Battery Pack ${index + 1}`}
name={`batterySN${index + 1}`}
value={serialNumber}
onChange={(e) =>
handleBatterySerialNumberChange(index, e.target.value)
}
onKeyDown={(e) => handleBatterySnKeyDown(e, index)}
inputRef={(el) => (batterySnRefs.current[index] = el)}
variant="outlined"
fullWidth
placeholder={canEdit ? 'Scan or enter serial number' : ''}
inputProps={{ readOnly: !canEdit }}
/>
</div>
))}
</>
)}
<div> <div>
<TextField <TextField
@ -486,10 +506,11 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
onChange={handleChange} onChange={handleChange}
variant="outlined" variant="outlined"
fullWidth fullWidth
inputProps={{ readOnly: !canEdit }}
/> />
</div> </div>
{currentUser.userType == UserType.admin && ( {canEdit && (
<> <>
<div> <div>
<TextField <TextField
@ -533,21 +554,23 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
marginTop: 10 marginTop: 10
}} }}
> >
<Button {canEdit && (
variant="contained" <Button
onClick={handleSubmit} variant="contained"
sx={{ onClick={handleSubmit}
marginLeft: '10px' sx={{
}} marginLeft: '10px'
disabled={!areRequiredFieldsFilled()} }}
> disabled={!areRequiredFieldsFilled()}
<FormattedMessage >
id="applyChanges" <FormattedMessage
defaultMessage="Apply Changes" id="applyChanges"
/> defaultMessage="Apply Changes"
</Button> />
</Button>
)}
{currentUser.userType == UserType.admin && ( {canEdit && (
<Button <Button
variant="contained" variant="contained"
onClick={handleDelete} onClick={handleDelete}

View File

@ -474,16 +474,18 @@ function SodioHomeInstallation(props: singleInstallationProps) {
} }
/> />
<Route {currentUser.userType !== UserType.client && (
path={routes.log} <Route
element={ path={routes.log}
<Log element={
errorLoadingS3Data={errorLoadingS3Data} <Log
id={props.current_installation.id} errorLoadingS3Data={errorLoadingS3Data}
status={props.current_installation.status} id={props.current_installation.id}
></Log> status={props.current_installation.status}
} ></Log>
/> }
/>
)}
<Route <Route
path={routes.live} path={routes.live}
@ -497,18 +499,20 @@ function SodioHomeInstallation(props: singleInstallationProps) {
} }
/> />
<Route {currentUser.userType !== UserType.client && (
path={routes.batteryview + '/*'} <Route
element={ path={routes.batteryview + '/*'}
<BatteryViewSodioHome element={
values={values} <BatteryViewSodioHome
s3Credentials={s3Credentials} values={values}
installationId={props.current_installation.id} s3Credentials={s3Credentials}
installation={props.current_installation} installationId={props.current_installation.id}
connected={connected} installation={props.current_installation}
></BatteryViewSodioHome> connected={connected}
} ></BatteryViewSodioHome>
></Route> }
/>
)}
{currentUser.userType == UserType.admin && ( {currentUser.userType == UserType.admin && (
<Route <Route
@ -559,16 +563,14 @@ function SodioHomeInstallation(props: singleInstallationProps) {
} }
/> />
{currentUser.userType == UserType.admin && ( <Route
<Route path={routes.report}
path={routes.report} element={
element={ <WeeklyReport
<WeeklyReport installationId={props.current_installation.id}
installationId={props.current_installation.id} />
/> }
} />
/>
)}
<Route <Route
path={'*'} path={'*'}

View File

@ -118,7 +118,6 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
value: 'log', value: 'log',
label: <FormattedMessage id="log" defaultMessage="Log" /> label: <FormattedMessage id="log" defaultMessage="Log" />
}, },
{ {
value: 'manage', value: 'manage',
label: ( label: (
@ -128,14 +127,12 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
/> />
) )
}, },
{ {
value: 'information', value: 'information',
label: ( label: (
<FormattedMessage id="information" defaultMessage="Information" /> <FormattedMessage id="information" defaultMessage="Information" />
) )
}, },
{ {
value: 'configuration', value: 'configuration',
label: ( label: (
@ -164,6 +161,45 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
) )
} }
] ]
: currentUser.userType == UserType.partner
? [
{
value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" />
},
{
value: 'overview',
label: <FormattedMessage id="overview" defaultMessage="Overview" />
},
{
value: 'batteryview',
label: (
<FormattedMessage
id="batteryview"
defaultMessage="Battery View"
/>
)
},
{
value: 'log',
label: <FormattedMessage id="log" defaultMessage="Log" />
},
{
value: 'information',
label: (
<FormattedMessage id="information" defaultMessage="Information" />
)
},
{
value: 'report',
label: (
<FormattedMessage
id="report"
defaultMessage="Report"
/>
)
}
]
: [ : [
{ {
value: 'live', value: 'live',
@ -178,14 +214,24 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
label: ( label: (
<FormattedMessage id="information" defaultMessage="Information" /> <FormattedMessage id="information" defaultMessage="Information" />
) )
},
{
value: 'report',
label: (
<FormattedMessage
id="report"
defaultMessage="Report"
/>
)
} }
]; ];
const tabs = const inInstallationView =
currentTab != 'list' && currentTab != 'list' &&
currentTab != 'tree' && currentTab != 'tree' &&
!location.pathname.includes('folder') && !location.pathname.includes('folder');
currentUser.userType == UserType.admin
const tabs = inInstallationView && currentUser.userType == UserType.admin
? [ ? [
{ {
value: 'list', value: 'list',
@ -216,7 +262,6 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
value: 'log', value: 'log',
label: <FormattedMessage id="log" defaultMessage="Log" /> label: <FormattedMessage id="log" defaultMessage="Log" />
}, },
{ {
value: 'manage', value: 'manage',
label: ( label: (
@ -226,7 +271,6 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
/> />
) )
}, },
{ {
value: 'information', value: 'information',
label: ( label: (
@ -261,10 +305,7 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
) )
} }
] ]
: currentTab != 'list' && : inInstallationView && currentUser.userType == UserType.partner
currentTab != 'tree' &&
!location.pathname.includes('folder') &&
currentUser.userType == UserType.client
? [ ? [
{ {
value: 'list', value: 'list',
@ -282,12 +323,67 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
value: 'overview', value: 'overview',
label: <FormattedMessage id="overview" defaultMessage="Overview" /> label: <FormattedMessage id="overview" defaultMessage="Overview" />
}, },
{
value: 'batteryview',
label: (
<FormattedMessage
id="batteryview"
defaultMessage="Battery View"
/>
)
},
{
value: 'log',
label: <FormattedMessage id="log" defaultMessage="Log" />
},
{ {
value: 'information', value: 'information',
label: ( label: (
<FormattedMessage id="information" defaultMessage="Information" /> <FormattedMessage id="information" defaultMessage="Information" />
) )
},
{
value: 'report',
label: (
<FormattedMessage
id="report"
defaultMessage="Report"
/>
)
}
]
: inInstallationView && currentUser.userType == UserType.client
? [
{
value: 'list',
icon: <ListIcon id="mode-toggle-button-list-icon" />
},
{
value: 'tree',
icon: <AccountTreeIcon id="mode-toggle-button-tree-icon" />
},
{
value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" />
},
{
value: 'overview',
label: <FormattedMessage id="overview" defaultMessage="Overview" />
},
{
value: 'information',
label: (
<FormattedMessage id="information" defaultMessage="Information" />
)
},
{
value: 'report',
label: (
<FormattedMessage
id="report"
defaultMessage="Report"
/>
)
} }
] ]
: [ : [