Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
T
Tia-dev
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dida Adams Arizona
Tia-dev
Commits
c0f39076
Commit
c0f39076
authored
Jan 23, 2026
by
Hardiansyah
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix historical
parent
c9866a8e
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
181 additions
and
69 deletions
+181
-69
index.js
src/api/index.js
+10
-0
ReportHistorical.js
src/container/Reports/ReportHistorical.js
+8
-4
AutocompleteField.js
src/library/AutocompleteField.js
+1
-1
ContentContainer.js
src/library/ContentContainer.js
+1
-3
DDLCompany.js
src/library/Dropdown/DDLCompany.js
+43
-60
Utils.js
src/library/Utils.js
+47
-1
services.js
src/utils/services.js
+71
-0
No files found.
src/api/index.js
View file @
c0f39076
...
...
@@ -87,6 +87,16 @@ const create = (type = "") => {
// console.tron.log(url)
})
api
.
addResponseTransform
(
response
=>
{
const
msg
=
response
.
data
?.
message
||
""
if
(
msg
.
includes
(
"Someone Logged In"
)
||
msg
.
includes
(
"Token Expired"
))
{
localStorage
.
removeItem
(
Constant
.
TOKEN
)
window
.
location
.
reload
()
return
}
})
// ------
// STEP 2
// ------
...
...
src/container/Reports/ReportHistorical.js
View file @
c0f39076
...
...
@@ -93,7 +93,7 @@ class ReportHistorical extends Component {
}))
}
showAlert
=
(
message
,
severity
=
'success'
)
=>
{
showAlert
=
(
message
,
severity
=
Constant
.
ALERT_SEVIRITY
.
SUCCESS
)
=>
{
this
.
setState
({
showAlert
:
true
,
alertMessage
:
message
,
...
...
@@ -107,8 +107,12 @@ class ReportHistorical extends Component {
handleDownload
=
async
()
=>
{
try
{
this
.
setLoading
(
true
)
const
{
data
}
=
this
.
state
if
(
!
data
?.
company_id
)
{
this
.
showAlert
(
'Data is not complete !'
,
Constant
.
ALERT_SEVIRITY
.
WARNING
);
return
}
this
.
setLoading
(
true
)
const
payload
=
{
report_id
:
data
.
report_id
?.
id
,
company_id
:
data
.
company_id
?.
map
(
c
=>
c
.
id
).
join
(
','
),
...
...
@@ -125,12 +129,12 @@ class ReportHistorical extends Component {
downloadFileBlob(fileName, blob)
}
this.showAlert('Download Berhasil'
, 'success'
);
this.showAlert('Download Berhasil');
})
} catch (error) {
// Show error alert
this.showAlert(`
Gagal
menyimpan
:
$
{
error
.
message
}
`,
'error'
);
this.showAlert(`
Gagal
menyimpan
:
$
{
error
.
message
}
`,
Constant.ALERT_SEVIRITY.ERROR
);
}
};
...
...
src/library/AutocompleteField.js
View file @
c0f39076
...
...
@@ -90,7 +90,7 @@ const AutocompleteField = ({
onChange
=
{
onChange
}
value
=
{
multiple
?
(
value
||
[])
:
(
value
||
null
)}
id
=
{
id
}
disableClearable
=
{
!
multiple
&&
disableClearable
}
disableClearable
=
{
disableClearable
}
disableCloseOnSelect
=
{
multiple
}
style
=
{
style
}
disabled
=
{
disabled
}
...
...
src/library/ContentContainer.js
View file @
c0f39076
...
...
@@ -29,9 +29,7 @@ class ContentContainer extends Component {
{
isLoading
&&
(
<
OverlayLoader
isLoading
=
{
isLoading
}
{...
loaderProps
}
/
>
)}
<
Header
title
=
{
title
}
/
>
{
title
&&
<
Header
title
=
{
title
}
/>
}
{
children
}
<
/div
>
);
...
...
src/library/Dropdown/DDLCompany.js
View file @
c0f39076
...
...
@@ -4,96 +4,88 @@ import AutocompleteField from '../AutocompleteField';
import
api
from
'../../api'
;
class
DDLCompany
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
selectedValue
:
props
.
multiple
?
(
props
.
value
||
[])
:
(
props
.
value
||
null
),
companies
:
[],
isLoading
:
false
,
};
}
state
=
{
companies
:
[],
selectedValue
:
this
.
props
.
multiple
?
[]
:
null
,
isLoading
:
false
,
};
componentDidMount
()
{
this
.
getCompanyActive
();
}
componentDidUpdate
(
prevProps
,
prevState
)
{
// Value dikontrol parent
if
(
prevProps
.
value
!==
this
.
props
.
value
)
{
this
.
syncValueWithCompanies
(
this
.
props
.
value
);
}
// Companies berubah (hasil API)
if
(
prevState
.
companies
!==
this
.
state
.
companies
)
{
// 🔁 value dari parent berubah ATAU companies selesai load
if
(
prevProps
.
value
!==
this
.
props
.
value
||
prevState
.
companies
!==
this
.
state
.
companies
)
{
this
.
syncValueWithCompanies
(
this
.
props
.
value
);
}
}
setLoading
=
(
isLoading
)
=>
{
this
.
setState
({
isLoading
});
}
}
;
getCompanyActive
=
async
()
=>
{
try
{
this
.
setLoading
(
true
);
const
res
ponse
=
await
api
.
create
().
getPerusahaanActive
();
const
data
=
res
ponse
?.
data
?.
data
||
[];
const
res
=
await
api
.
create
().
getPerusahaanActive
();
const
data
=
res
?.
data
?.
data
||
[];
const
companies
=
data
.
map
(
item
=>
({
id
:
String
(
item
.
company_id
),
name
:
item
.
company_name
,
}));
this
.
setState
({
companies
});
}
catch
(
err
)
{
console
.
error
(
'Failed to load companies'
,
err
);
this
.
setState
({
companies
},
()
=>
{
// ⭐ optional auto select index 0
if
(
this
.
props
.
autoSelectFirst
&&
!
this
.
props
.
value
&&
companies
.
length
>
0
)
{
this
.
handleChange
(
null
,
this
.
props
.
multiple
?
[
companies
[
0
]]
:
companies
[
0
]);
}
});
}
catch
(
e
)
{
console
.
error
(
e
);
this
.
setState
({
companies
:
[]
});
}
finally
{
this
.
setLoading
(
false
);
}
};
//
Sinkron value → referensi object dari companies
//
🔑 SINKRON VALUE ↔ OPTIONS (INI KUNCI UTAMA)
syncValueWithCompanies
=
(
value
)
=>
{
const
{
companies
}
=
this
.
state
;
const
{
multiple
}
=
this
.
props
;
if
(
!
value
||
companies
.
length
===
0
)
{
this
.
setState
({
selectedValue
:
multiple
?
[]
:
null
,
});
return
;
}
if
(
!
value
||
companies
.
length
===
0
)
return
;
if
(
multiple
)
{
const
synced
=
value
.
map
(
v
=>
companies
.
find
(
c
=>
String
(
c
.
id
)
===
String
(
v
.
id
))
)
.
map
(
v
=>
companies
.
find
(
c
=>
c
.
id
===
String
(
v
.
id
)))
.
filter
(
Boolean
);
this
.
setState
({
selectedValue
:
synced
});
}
else
{
const
matched
=
companies
.
find
(
c
=>
String
(
c
.
id
)
===
String
(
value
.
id
)
);
const
matched
=
companies
.
find
(
c
=>
c
.
id
===
String
(
value
.
id
));
this
.
setState
({
selectedValue
:
matched
||
null
});
}
};
// 🔁 SELALU KIRIM BALIK KE PARENT
handleChange
=
(
event
,
newValue
)
=>
{
const
{
onChange
,
onCompanyChange
,
name
,
multiple
}
=
this
.
props
;
this
.
setState
({
selectedValue
:
newValue
});
// Standard handler
if
(
onChange
)
{
onChange
(
event
,
newValue
,
name
);
}
// Backward compatibility
if
(
onCompanyChange
)
{
if
(
multiple
)
{
onCompanyChange
(
newValue
.
map
(
v
=>
v
.
id
));
...
...
@@ -103,29 +95,20 @@ class DDLCompany extends Component {
}
};
getSelectedCompanyValue
=
()
=>
{
const
{
selectedValue
}
=
this
.
state
;
const
{
multiple
}
=
this
.
props
;
return
multiple
?
selectedValue
.
map
(
v
=>
v
.
id
)
:
selectedValue
?.
id
||
null
;
};
render
()
{
const
{
label
=
'Company'
,
placeholder
=
'Select Company'
,
disabled
=
false
,
required
=
false
,
error
=
false
,
label
,
placeholder
,
disabled
,
required
,
error
,
helperText
,
style
=
{
width
:
250
}
,
margin
=
'normal'
,
style
,
margin
,
multiple
,
}
=
this
.
props
;
const
{
selectedValue
,
companies
,
isLoading
}
=
this
.
state
;
const
{
companies
,
selectedValue
,
isLoading
}
=
this
.
state
;
return
(
<
AutocompleteField
...
...
@@ -142,17 +125,14 @@ class DDLCompany extends Component {
margin
=
{
margin
}
multiple
=
{
multiple
}
showCheckbox
=
{
multiple
}
isL
oading
=
{
isLoading
}
l
oading
=
{
isLoading
}
/
>
);
}
}
DDLCompany
.
propTypes
=
{
value
:
PropTypes
.
oneOfType
([
PropTypes
.
object
,
PropTypes
.
array
,
]),
value
:
PropTypes
.
oneOfType
([
PropTypes
.
object
,
PropTypes
.
array
]),
onChange
:
PropTypes
.
func
,
onCompanyChange
:
PropTypes
.
func
,
name
:
PropTypes
.
string
,
...
...
@@ -168,13 +148,16 @@ DDLCompany.propTypes = {
helperText
:
PropTypes
.
string
,
multiple
:
PropTypes
.
bool
,
autoSelectFirst
:
PropTypes
.
bool
,
};
DDLCompany
.
defaultProps
=
{
label
:
'Company'
,
placeholder
:
'Select Company'
,
style
:
{
width
:
250
},
margin
:
'normal'
,
multiple
:
false
,
autoSelectFirst
:
false
,
};
export
default
DDLCompany
;
src/library/Utils.js
View file @
c0f39076
...
...
@@ -26,4 +26,50 @@ export function downloadFileBlob(fileName, blobData) {
a
.
click
()
a
.
remove
()
window
.
URL
.
revokeObjectURL
(
url
)
}
\ No newline at end of file
}
/**
* @param {Object} location - Objek location dari props (this.props.location)
* @param {string} paramName - Nama key yang ingin diambil (misal: 'month')
* @param {any} defaultValue - Nilai kembalian jika data null/undefined
*/
export
const
getStateParam
=
(
location
,
paramName
=
null
,
defaultValue
=
null
)
=>
{
if
(
!
paramName
)
{
return
location
?.
state
??
defaultValue
;
}
return
location
?.
state
?.[
paramName
]
??
defaultValue
;
};
export
const
formatters
=
{
// Untuk format Infinity
infinity
:
{
month
:
(
val
)
=>
String
(
val
===
undefined
||
val
===
'Infinity'
||
val
===
'-Infinity'
?
"0.0"
:
Number
(
val
).
toFixed
(
2
)),
totalCY
:
(
val
)
=>
String
(
val
===
undefined
||
val
===
'Infinity'
||
val
===
'-Infinity'
?
"0.0"
:
Number
(
val
).
toFixed
(
2
)),
totalOther
:
(
val
)
=>
String
(
val
!==
''
&&
val
!==
'Infinity'
&&
val
!==
'-Infinity'
?
Number
(
val
).
toFixed
(
2
)
:
val
)
},
// Untuk format .value property
value
:
{
month
:
(
val
)
=>
String
(
val
?.
value
===
undefined
?
val
:
Number
(
val
.
value
).
toFixed
(
1
)),
total
:
(
val
)
=>
String
(
val
!==
''
?
Number
(
val
).
toFixed
(
1
)
:
val
)
}
};
// ===== HELPER FUNCTIONS =====
export
const
createMonthData
=
(
item
,
startIdx
,
formatFn
)
=>
{
const
monthNames
=
[
'january'
,
'february'
,
'march'
,
'april'
,
'may'
,
'june'
,
'july'
,
'august'
,
'september'
,
'october'
,
'november'
,
'december'
];
const
months
=
{};
monthNames
.
forEach
((
month
,
idx
)
=>
{
months
[
month
]
=
formatFn
(
item
[
startIdx
+
idx
]);
});
return
months
;
};
\ No newline at end of file
src/utils/services.js
0 → 100644
View file @
c0f39076
import
api
from
"../api"
;
import
Constant
from
"../library/Constant"
;
const
handleResponse
=
(
response
)
=>
{
// 1. Handling Sukses
if
(
response
.
ok
&&
response
.
data
?.
status
===
"success"
)
{
return
response
.
data
.
data
;
}
// 2. Ambil pesan asli
const
serverMessage
=
response
.
data
?.
message
||
response
.
data
?.
error
||
response
.
problem
||
"Gagal"
;
// 3. Masking bahasa teknis backend
let
finalMessage
=
serverMessage
;
if
(
typeof
serverMessage
===
'string'
&&
(
serverMessage
.
includes
(
"java.lang"
)
||
serverMessage
.
includes
(
"FormatException"
)
||
serverMessage
.
includes
(
"sql"
)
))
{
finalMessage
=
"Terjadi kesalahan format data pada sistem."
;
}
const
error
=
new
Error
(
finalMessage
);
error
.
tipe
=
(
response
.
status
>=
400
&&
response
.
status
<
500
)
?
'warning'
:
'error'
;
error
.
isApiError
=
true
;
error
.
originalMessage
=
serverMessage
;
throw
error
;
};
/**
* Wrapper agar komponen bisa memilih mau pakai data saja atau errornya juga.
* Menghilangkan kebutuhan try-catch di komponen.
*/
const
wrapService
=
(
promise
)
=>
{
return
promise
.
then
(
res
=>
{
return
{
data
:
handleResponse
(
res
),
error
:
null
};
})
.
catch
((
err
)
=>
{
console
.
error
(
"API_LOG:"
,
err
.
originalMessage
||
err
.
message
);
return
{
data
:
null
,
error
:
{
message
:
err
.
message
,
tipe
:
err
.
tipe
}
};
});
};
// --- EXPORTED SERVICES ---
export
const
fetchMenuPermission
=
(
menuName
)
=>
wrapService
(
api
.
create
().
getPermission
({
menu
:
menuName
}));
export
const
fetchDetailRole
=
(
roleId
)
=>
wrapService
(
api
.
create
().
getDetailRole
(
roleId
));
export
const
fetchDetailUser
=
()
=>
{
const
userId
=
localStorage
.
getItem
(
Constant
.
USER
);
return
wrapService
(
api
.
create
().
getDetailUser
(
userId
));
};
export
const
fetchApprover
=
()
=>
wrapService
(
api
.
create
().
checkApprover
());
export
const
fetchLastPeriod
=
(
companyId
)
=>
wrapService
(
api
.
create
().
getLastPeriod
(
companyId
));
export
const
fetchRevision
=
(
payload
)
=>
wrapService
(
api
.
create
().
getRevision
(
payload
));
export
const
fetchSubmission
=
(
payload
)
=>
wrapService
(
api
.
create
().
getSubmission
(
payload
));
export
const
fetchListApprover
=
(
report
,
monthlyReportId
)
=>
{
return
wrapService
(
api
.
create
().
getListApprover
(
report
,
monthlyReportId
));
}
export
const
fetchDetailReportCF
=
(
payload
)
=>
wrapService
(
api
.
create
().
getDetailReportCF
(
payload
));
export
const
fetchPLID
=
(
payload
)
=>
wrapService
(
api
.
create
().
getPLID
(
payload
));
export
const
fetchHierarkiCreateReportPLMB
=
(
payload
)
=>
wrapService
(
api
.
create
().
getHierarkiCreateReportPLMB
(
payload
));
export
const
fetchFRID
=
(
payload
)
=>
wrapService
(
api
.
create
().
getFRID
(
payload
));
export
const
fetchDownloadFile
=
(
payload
)
=>
wrapService
(
api
.
create
().
createDownloadFile
(
payload
));
export
const
fetchZipReport
=
(
downloadedFileReportId
)
=>
wrapService
(
api
.
create
().
createZipReport
(
downloadedFileReportId
));
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment