Guest User

Untitled

a guest
Oct 18th, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.34 KB | None | 0 0
  1. // renders the preview of an attachment inside a modal
  2. // -- props --
  3. // url: Used for getting the attachments of a loan application
  4. // sort_value: To preserve the sort type from the attachments table
  5. // attachment: The attachment to be previewed
  6. // attachments: The array of attachments to be displayed in the preview sidebar
  7.  
  8. const propTypes = {
  9. attachment: React.PropTypes.object,
  10. attachments: React.PropTypes.array,
  11. document: React.PropTypes.object,
  12. loan_application: React.PropTypes.object.isRequired,
  13. loan_application: React.PropTypes.object.isRequired,
  14. };
  15.  
  16. const defaultProps = {
  17. url: '',
  18. attachmentUrl: '',
  19. attachments: [],
  20. sort_value: 'date_descending',
  21. document: {},
  22. attachment: {},
  23. };
  24.  
  25. class RequirementsHubAttachmentModal extends React.Component {
  26. constructor(props) {
  27. super(props);
  28.  
  29. let { type, kind, number, expiration_date } = this.props.document;
  30.  
  31. this.state = {
  32. rotation: 0,
  33. zoom: false,
  34. loading: false,
  35. processing: false,
  36. attachmentUrl: this.props.attachment.url,
  37. sort_value: this.props.sort_value,
  38. document: {
  39. type: type,
  40. kind: kind,
  41. number: number,
  42. expiration_date: expiration_date,
  43. },
  44. attachment: this.props.attachment,
  45. attachments: this.props.attachments,
  46. asCollection: false,
  47. success: '',
  48. status: 'initialized',
  49. };
  50.  
  51. this.zoom = this.zoom.bind(this);
  52. this.rotate = this.rotate.bind(this);
  53. this.onSortChange = this.onSortChange.bind(this);
  54. this.fetchSuccess = this.fetchSuccess.bind(this);
  55. this.saveRotation = this.saveRotation.bind(this);
  56. this.rotationSuccess = this.rotationSuccess.bind(this);
  57. this.updateAttachment = this.updateAttachment.bind(this);
  58. this.handleDocumentSubmit = this.handleDocumentSubmit.bind(this);
  59. this.handleChange = this.handleChange.bind(this);
  60. this.buildFilePayload = this.buildFilePayload.bind(this);
  61. this.uploadAttachmentSuccess = this.uploadAttachmentSuccess.bind(this);
  62. this.setAttributesAfterUpload = this.setAttributesAfterUpload.bind(this);
  63. this.handleUploadAttachment = this.handleUploadAttachment.bind(this);
  64. }
  65.  
  66.  
  67. // when the component updates, fetch the attachment URL if the attachmentURL
  68. // is ''. The attachmentURL is set back to '' in updateAttachment() which is
  69. // called when an attachment in the sidebar is clicked
  70. componentDidUpdate(previousProps, previousState) {
  71. if (this.state.attachmentUrl == '') {
  72. }
  73. }
  74.  
  75. onSortChange(e) {
  76. e.preventDefault();
  77. this.setState({
  78. loading: true,
  79. sort_value: e.target.value,
  80. });
  81.  
  82. let loan_application_id = this.state.attachment.loan_application_id;
  83. $.ajax({
  84. url: Routing.api_v1_loan_application_attachments(loan_application_id),
  85. method: 'GET',
  86. data: { sort: e.target.value },
  87. success: this.fetchSuccess,
  88. });
  89. }
  90.  
  91. fetchSuccess(attachments) {
  92. this.setState({
  93. loading: false,
  94. attachments: attachments,
  95. });
  96. }
  97.  
  98. rotationSuccess(response) {
  99. this.setState({
  100. processing: false,
  101. attachmentUrl: '',
  102. attachment: response.attachment,
  103. })
  104. }
  105.  
  106. saveRotation() {
  107. this.setState({ processing: true })
  108. $.ajax({
  109. type: 'PUT',
  110. url: Routing.api_v1_loan_application_attachment(
  111. this.state.attachment.loan_application_id,
  112. this.state.attachment.id,
  113. ),
  114. data: {
  115. attachment: { rotation: this.state.rotation }
  116. },
  117. success: this.rotationSuccess
  118. })
  119. }
  120.  
  121. rotate() {
  122. let rotation = (this.state.rotation + 90) % 360;
  123. this.setState({rotation});
  124. }
  125.  
  126. zoom() {
  127. let zoom = !this.state.zoom
  128. this.setState({zoom})
  129. }
  130.  
  131. updateAttachment(attachment) {
  132. this.setState({ attachment, attachmentUrl: '', rotation: 0, zoom: false })
  133. }
  134.  
  135. get height() {
  136. if (this.state.rotation % 180 == 0) {
  137. return 'auto'
  138. }
  139.  
  140. if (this.state.zoom == false) {
  141. return this.refs.scrollarea.clientWidth
  142. }
  143. }
  144.  
  145. get width() {
  146. if (this.height != 'auto') {
  147. return 'auto'
  148. }
  149. return this.state.zoom ? "auto" : "100%"
  150. }
  151.  
  152. get imageStyle() {
  153. return {
  154. width: this.width,
  155. height: this.height,
  156. transformOrigin: 'top left',
  157. transform: this.transform,
  158. }
  159. }
  160.  
  161. get transform() {
  162. if (this.state.rotation == 90) {
  163. return `rotate(${this.state.rotation}deg) translateY(-100%)`
  164. }
  165. if (this.state.rotation == 180) {
  166. return `rotate(${this.state.rotation}deg) translate(-100%, -100%)`
  167. }
  168. if (this.state.rotation == 270) {
  169. return `rotate(${this.state.rotation}deg) translateX(-100%)`
  170. }
  171. }
  172.  
  173. get sortOptions() {
  174. return SelectOptions.attachment_sort_types;
  175. }
  176.  
  177. get sortClassName() {
  178. return classNames(
  179. 'display-flex', 'justifyContent-flex-end',
  180. 'marginLeft-m', 'marginRight-m', 'paddingTop-s', 'paddingBottom-s',
  181. 'borderBottomWidth-1', 'borderStyle-solid', 'borderBottomColor-grey-l'
  182. )
  183. }
  184.  
  185. get sidePanelClassName() {
  186. return classNames(
  187. 'float-left', 'width-30p', 'height-100p', 'padding-m', 'borderLeftWidth-1', 'borderBottomWidth-1', 'borderStyle-solid', 'borderBottomColor-grey-l'
  188. )
  189. }
  190.  
  191. get rotationButtonClassName() {
  192. return classNames(
  193. "btn",
  194. "btn-blue",
  195. "btn-s cursor-pointer",
  196. {
  197. "btn-outlined": !this.state.processing
  198. },
  199. {
  200. "btn--loading": this.state.processing
  201. }
  202. )
  203. }
  204.  
  205. renderSaveRotationButton() {
  206. if (this.state.rotation == 0) return;
  207.  
  208. return (
  209. <div>
  210. <a
  211. className={this.rotationButtonClassName}
  212. onClick={this.saveRotation}
  213. >
  214. Save Rotation
  215. </a>
  216. </div>
  217. );
  218. }
  219.  
  220. // returns the content for the preview pane
  221. renderContent() {
  222. if ( !this.state.attachment.url && !this.state.attachmentUrl ) {
  223. return <h1>Please Upload Attachment</h1>
  224. } else if ( !this.state.attachmentUrl ) {
  225. return <div className="loading marginTop-l" />
  226. }
  227.  
  228. if (this.state.attachment.mime_type === 'image') {
  229. // return an image if the attachment is an image
  230. return (
  231. <div>
  232. <div className="attachment-actions">
  233. {this.renderSaveRotationButton()}
  234. <div
  235. onClick={this.rotate}
  236. className="attachment-action attachment-action-rotate"
  237. />
  238. <div
  239. onClick={this.zoom}
  240. className="attachment-action attachment-action-zoom"
  241. />
  242. </div>
  243. <img
  244. ref="image"
  245. style={this.imageStyle}
  246. className="preventTextSelect"
  247. src={this.state.attachmentUrl}
  248. />
  249. </div>
  250. )
  251. } else {
  252. // otherwise return an iframe
  253. return (
  254. <iframe
  255. className="height-100p width-100p"
  256. src={this.state.attachmentUrl}
  257. />
  258. );
  259. }
  260. }
  261.  
  262. handleChange(event) {
  263. let newValues = { ...this.state }
  264. newValues.document[event.target.name] = event.target.value
  265. this.setState(newValues)
  266. }
  267.  
  268. // setAttributesAfterUpload(response) {
  269. // let documentValues = this.state.document
  270. // }
  271.  
  272. handleUploadSuccess() {
  273. $.ajax({
  274. type: 'GET',
  275. url: Routing.api_v1_lead_requirements_hub_index(this.props.lead.id),
  276. success: this.setAttributesAfterUpload
  277. });
  278. }
  279.  
  280. buildFilePayload() {
  281. let formData = new FormData();
  282.  
  283. formData.append('documents[]type', this.state.document.type)
  284. formData.append('documents[]kind', this.state.document.kind)
  285. formData.append('documents[]number', this.state.document.number)
  286. formData.append('documents[]status', 'submitted')
  287. formData.append('documents[]source', 'fcc')
  288. formData.append(
  289. 'documents[]expiration_date',
  290. this.state.document.expiration_date)
  291. formData.append(
  292. 'documents[]attachment_attributes[attachment_file]',
  293. this.refs.upload_attachment.files[0]
  294. )
  295. formData.append(
  296. 'documents[]attachment_attributes[loan_application_id]',
  297. this.props.loan_application.id
  298. )
  299. return formData;
  300. }
  301.  
  302. handleDocumentSubmit(event) {
  303. event.preventDefault();
  304. debugger
  305.  
  306. $.ajax({
  307. type: 'POST',
  308. url: Routing.import_api_v1_lead_documents(this.props.lead.id),
  309. data: this.buildFilePayload(),
  310. contentType: false,
  311. processData: false,
  312. success: this.handleUploadSuccess,
  313. error: (errors) => this.setState({ errors: errors.responseJSON.errors })
  314. });
  315. }
  316.  
  317. renderDocumentOptions(document) {
  318. return (
  319. <form onSubmit={this.handleDocumentSubmit}>
  320. <div className="fontColor-green">{this.state.success}</div>
  321. <div className="fontColor-red">{this.state.errors}</div>
  322. <input type="submit" className="btn btn-green btn-small fontSize-xxxxs" value="Save" />
  323. <Select
  324. name="type"
  325. ref="type"
  326. options={SelectOptions.document_type}
  327. value={this.state.document.type}
  328. onChange={this.handleChange}
  329. placeholder='Choose Document Kind'
  330. />
  331. <hr/>
  332. <Select
  333. name="kind"
  334. ref="kind"
  335. options={SelectOptions.document_kind}
  336. value={this.state.document.kind}
  337. onChange={this.handleChange}
  338. placeholder='Select Document Type'
  339. />
  340. <TextInput
  341. type="text"
  342. name="number"
  343. ref="number"
  344. value={this.state.document.number}
  345. onChange={this.handleChange}
  346. />
  347. <DateSelect
  348. name="expiration_date"
  349. ref="expiration_date"
  350. value={this.state.document.expiration_date}
  351. onChange={this.handleChange}
  352. />
  353. </form>
  354. )
  355. }
  356.  
  357. uploadAttachmentSuccess(attachments) {
  358. const length = attachments.attachments.length;
  359. const base = length > 1 ? `${length} ` : "Attachment";
  360. Alert(`${base} uploaded successfully!`);
  361. this.setState({
  362. attachmentUrl: attachments.attachments[0].expiring_url,
  363. attachment: attachments.attachments[0],
  364. status: 'initialized'
  365. });
  366. }
  367.  
  368. buildAttachmentPayload() {
  369. let formData = new FormData();
  370. const files = this.refs.upload_attachment.files;
  371. for (var i = 0; i < files.length; i++) {
  372. formData.append('attachment_files[]', files[i], files[i].name);
  373. }
  374. return formData;
  375. }
  376.  
  377. handleUploadAttachment(event) {
  378. event.preventDefault();
  379. this.setState({ status: "processing" })
  380.  
  381. $.ajax({
  382. url: Routes.api_loan_application_attachments_path(
  383. this.props.loan_application.id
  384. ),
  385. method: 'POST',
  386. data: this.buildAttachmentPayload(),
  387. contentType: false,
  388. processData: false,
  389. success: this.uploadAttachmentSuccess,
  390. error: this.uploadError
  391. })
  392. }
  393.  
  394. buttonClassName() {
  395. return classNames(
  396. "backgroundColor-green",
  397. {
  398. "btn--loading": this.state.status === "processing"
  399. }
  400. )
  401.  
  402. }
  403. renderUploadAttachmentButton() {
  404. return (
  405. <FileInputButton
  406. ref="upload_attachment"
  407. key={this.state.input_key}
  408. buttonText="Upload Document"
  409. onChange={this.handleAttachmentUpload}
  410. name="attachment[attachment_file]"
  411. buttonClassName={this.buttonClassName()}
  412. />
  413. );
  414. }
  415.  
  416. renderAttachmentForm() {
  417. return (
  418. <section className="maginTop-xl">
  419. <h5>Attach Document To</h5>
  420. {this.renderDocumentOptions()}
  421. {this.renderUploadAttachmentButton()}
  422. </section>
  423. )
  424. }
  425.  
  426. renderAttachments() {
  427. if (this.state.loading) {
  428. return <div className="loading paddingTop-xl" />
  429. } else {
  430. return this.state.attachments.map(function(attachment, i) {
  431. return (
  432. <RequirementsHubAttachment
  433. key={i}
  434. onClick={this.updateAttachment}
  435. className="attachment-s marginBottom-s"
  436. {...attachment}
  437. />
  438. )
  439. }.bind(this))
  440. }
  441. }
  442.  
  443. renderSortAttachments() {
  444. return (
  445. <div className='display-flex alignItems-center'>
  446. <div>
  447. <label className='marginRight-s marginBottom-0'>Sort:</label>
  448. </div>
  449. <div>
  450. <Select
  451. className='select-simple'
  452. options={this.sortOptions}
  453. value={this.state.sort_value}
  454. onChange={this.onSortChange}
  455. />
  456. </div>
  457. </div>
  458. );
  459. }
  460.  
  461. renderAttachmentsContainer() {
  462. return (
  463. <div className='height-80p overflowY-scroll'>
  464. <div className={this.sortClassName}>
  465. {this.renderSortAttachments()}
  466. </div>
  467. <div className="padding-m paddingTop-s">
  468. {this.renderAttachments()}
  469. </div>
  470. </div>
  471. );
  472. }
  473.  
  474. renderSidePanel() {
  475. return (
  476. <div className={this.sidePanelClassName}>
  477. <h4>Customer Documents</h4>
  478. {this.state.asCollection ? this.renderAttachmentsContainer() :
  479. this.renderAttachmentForm(this.state.document)}
  480. </div>
  481. );
  482. }
  483.  
  484. render() {
  485. return (
  486. <div className="clearfix height-100p">
  487. <div
  488. ref='viewport'
  489. className="float-left width-70p height-100p position-relative"
  490. >
  491. <div
  492. ref="scrollarea"
  493. className="overflow-scroll width-100p height-100p"
  494. >
  495. {this.renderContent()}
  496. </div>
  497. </div>
  498. {this.renderSidePanel()}
  499. </div>
  500. );
  501. }
  502. }
  503.  
  504. RequirementsHubAttachmentModal.propTypes = propTypes;
  505.  
  506. RequirementsHubAttachmentModal.defaultProps = defaultProps;
  507.  
  508. RequirementsHubAttachmentModal = asModal(RequirementsHubAttachmentModal, {className: 'modal-full-screen'})
Add Comment
Please, Sign In to add comment