GridEditModal.jsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import {
  4. Modal, ModalHeader, ModalBody, ModalFooter,
  5. } from 'reactstrap';
  6. import { withTranslation } from 'react-i18next';
  7. import geu from './GridEditorUtil';
  8. import BootstrapGrid from '../../models/BootstrapGrid';
  9. const resSizes = BootstrapGrid.ResponsiveSize;
  10. const resSizeObj = {
  11. [resSizes.XS_SIZE]: { iconClass: 'icon-screen-smartphone', displayText: 'grid_edit.smart_no' },
  12. [resSizes.SM_SIZE]: { iconClass: 'icon-screen-tablet', displayText: 'tablet' },
  13. [resSizes.MD_SIZE]: { iconClass: 'icon-screen-desktop', displayText: 'desktop' },
  14. };
  15. class GridEditModal extends React.Component {
  16. constructor(props) {
  17. super(props);
  18. this.state = {
  19. colsRatios: [6, 6],
  20. responsiveSize: BootstrapGrid.ResponsiveSize.XS_SIZE,
  21. show: false,
  22. // use when re-edit grid
  23. // gridHtml: '',
  24. };
  25. this.checkResposiveSize = this.checkResposiveSize.bind(this);
  26. this.checkColsRatios = this.checkColsRatios.bind(this);
  27. // use when re-edit grid
  28. // this.init = this.init.bind(this);
  29. this.show = this.show.bind(this);
  30. this.hide = this.hide.bind(this);
  31. this.cancel = this.cancel.bind(this);
  32. this.pasteCodedGrid = this.pasteCodedGrid.bind(this);
  33. this.renderSelectedGridPattern = this.renderSelectedGridPattern.bind(this);
  34. this.renderBreakPointSetting = this.renderBreakPointSetting.bind(this);
  35. }
  36. async checkResposiveSize(rs) {
  37. await this.setState({ responsiveSize: rs });
  38. }
  39. async checkColsRatios(cr) {
  40. await this.setState({ colsRatios: cr });
  41. }
  42. // use when re-edit grid
  43. // init(gridHtml) {
  44. // const initGridHtml = gridHtml;
  45. // this.setState({ gridHtml: initGridHtml });
  46. // }
  47. show(gridHtml) {
  48. // use when re-edit grid
  49. // this.init(gridHtml);
  50. this.setState({ show: true });
  51. }
  52. hide() {
  53. this.setState({ show: false });
  54. }
  55. cancel() {
  56. this.hide();
  57. }
  58. pasteCodedGrid() {
  59. const { colsRatios, responsiveSize } = this.state;
  60. const convertedHTML = geu.convertRatiosAndSizeToHTML(colsRatios, responsiveSize);
  61. const spaceTab = ' ';
  62. const pastedGridData = `::: editable-row\n<div class="container">\n${spaceTab}<div class="row">\n${convertedHTML}\n${spaceTab}</div>\n</div>\n:::`;
  63. if (this.props.onSave != null) {
  64. this.props.onSave(pastedGridData);
  65. }
  66. this.cancel();
  67. }
  68. renderSelectedGridPattern() {
  69. const colsRatios = this.state.colsRatios;
  70. return colsRatios.join(' - ');
  71. }
  72. renderBreakPointSetting() {
  73. const { t } = this.props;
  74. const output = Object.entries(resSizeObj).map((responsiveSizeForMap) => {
  75. return (
  76. <div key={responsiveSizeForMap[0]} className="custom-control custom-radio custom-control-inline">
  77. <input
  78. type="radio"
  79. className="custom-control-input"
  80. id={responsiveSizeForMap[1].displayText}
  81. value={responsiveSizeForMap[1].displayText}
  82. checked={this.state.responsiveSize === responsiveSizeForMap[0]}
  83. onChange={e => this.checkResposiveSize(responsiveSizeForMap[0])}
  84. />
  85. <label className="custom-control-label" htmlFor={responsiveSizeForMap[1].displayText}>
  86. <i className={`pr-1 ${responsiveSizeForMap[1].iconClass}`} />
  87. {t(responsiveSizeForMap[1].displayText)}
  88. </label>
  89. </div>
  90. );
  91. });
  92. return output;
  93. }
  94. renderGridDivisionMenu() {
  95. const gridDivisions = geu.mappingAllGridDivisionPatterns;
  96. const { t } = this.props;
  97. return (
  98. <div className="container">
  99. <div className="row">
  100. {gridDivisions.map((gridDivision) => {
  101. const numOfDivisions = gridDivision.numberOfGridDivisions;
  102. return (
  103. <div key={`${numOfDivisions}-divisions`} className="col-md-4 text-center">
  104. <h6 className="dropdown-header">{numOfDivisions} {t('grid_edit.division')}</h6>
  105. {gridDivision.mapping.map((gridOneDivision) => {
  106. const keyOfRow = `${numOfDivisions}-divisions-${gridOneDivision.join('-')}`;
  107. return (
  108. <button key={keyOfRow} className="dropdown-item" type="button" onClick={() => { this.checkColsRatios(gridOneDivision) }}>
  109. <div className="row">
  110. {gridOneDivision.map((god, i) => {
  111. const keyOfCol = `${keyOfRow}-${i}`;
  112. const className = `bg-info col-${god} border`;
  113. return <span key={keyOfCol} className={className}>{god}</span>;
  114. })}
  115. </div>
  116. </button>
  117. );
  118. })}
  119. </div>
  120. );
  121. })}
  122. </div>
  123. </div>
  124. );
  125. }
  126. renderPreview() {
  127. // TODO GW-3721 make objects and simplify all loops
  128. /* const prevSize = BootstrapGrid.ResponsiveSize;
  129. const prevSizeObj = {
  130. [prevSize.MD_SIZE]: {
  131. [prevSize.MD_SIZE]: {
  132. iconClass: 'icon-screen-desktop', prevClass: 'desktop-preview', prevText: 'Desktop', prevRender: this.renderNoBreakPreview(),
  133. },
  134. [prevSize.SM_SIZE]: {
  135. iconClass: 'icon-screen-tablet', prevClass: 'tablet-preview', prevText: 'Tablet', prevRender: this.renderBreakPreview(),
  136. },
  137. [prevSize.XS_SIZE]: {
  138. iconClass: 'icon-screen-smartphone', prevClass: 'mobile-preview', prevText: 'Smartphone', prevRender: this.renderBreakPreview(),
  139. },
  140. },
  141. [prevSize.SM_SIZE]: {
  142. [prevSize.MD_SIZE]: {
  143. iconClass: 'icon-screen-desktop', prevClass: 'desktop-preview', prevText: 'Desktop', prevRender: this.renderNoBreakPreview(),
  144. },
  145. [prevSize.SM_SIZE]: {
  146. iconClass: 'icon-screen-tablet', prevClass: 'tablet-preview', prevText: 'Tablet', prevRender: this.renderNoBreakPreview(),
  147. },
  148. [prevSize.XS_SIZE]: {
  149. iconClass: 'icon-screen-smartphone', prevClass: 'mobile-preview', prevText: 'Smartphone', prevRender: this.renderBreakPreview(),
  150. },
  151. },
  152. [prevSize.MD_SIZE]: {
  153. [prevSize.MD_SIZE]: {
  154. iconClass: 'icon-screen-desktop', prevClass: 'desktop-preview', prevText: 'Desktop', prevRender: this.renderNoBreakPreview(),
  155. },
  156. [prevSize.SM_SIZE]: {
  157. iconClass: 'icon-screen-tablet', prevClass: 'tablet-preview', prevText: 'Tablet', prevRender: this.renderNoBreakPreview(),
  158. },
  159. [prevSize.XS_SIZE]: {
  160. iconClass: 'icon-screen-smartphone', prevClass: 'mobile-preview', prevText: 'Smartphone', prevRender: this.renderNoBreakPreview(),
  161. },
  162. },
  163. }; */
  164. const { t } = this.props;
  165. if (this.state.responsiveSize === BootstrapGrid.ResponsiveSize.MD_SIZE) {
  166. return (
  167. <div className="row">
  168. <div className="col-lg-6">
  169. <label className="d-block mt-2"><i className="pr-2 icon-screen-desktop"></i>{t('desktop')}</label>
  170. <div className="desktop-preview d-block">
  171. {this.renderNoBreakPreview()}
  172. </div>
  173. </div>
  174. <div className="col-lg-3">
  175. <label className="d-block mt-2"><i className="pr-2 icon-screen-tablet"></i>{t('tablet')}</label>
  176. <div className="tablet-preview d-block">
  177. {this.renderBreakPreview()}
  178. </div>
  179. </div>
  180. <div className="col-lg-3">
  181. <label className="d-block mt-2"><i className="pr-2 icon-screen-smartphone"></i>{t('phone')}</label>
  182. <div className="mobile-preview d-block">
  183. {this.renderBreakPreview()}
  184. </div>
  185. </div>
  186. </div>
  187. );
  188. }
  189. if (this.state.responsiveSize === BootstrapGrid.ResponsiveSize.SM_SIZE) {
  190. return (
  191. <div className="row">
  192. <div className="col-lg-6">
  193. <label className="d-block mt-2"><i className="pr-2 icon-screen-desktop"></i>{t('desktop')}</label>
  194. <div className="desktop-preview d-block">
  195. {this.renderNoBreakPreview()}
  196. </div>
  197. </div>
  198. <div className="col-lg-3">
  199. <label className="d-block mt-2"><i className="pr-2 icon-screen-tablet"></i>{t('tablet')}</label>
  200. <div className="tablet-preview d-block">
  201. {this.renderNoBreakPreview()}
  202. </div>
  203. </div>
  204. <div className="col-lg-3">
  205. <label className="d-block mt-2"><i className="pr-2 icon-screen-smartphone"></i>{t('phone')}</label>
  206. <div className="mobile-preview d-block">
  207. {this.renderBreakPreview()}
  208. </div>
  209. </div>
  210. </div>
  211. );
  212. }
  213. if (this.state.responsiveSize === BootstrapGrid.ResponsiveSize.XS_SIZE) {
  214. return (
  215. <div className="row">
  216. <div className="col-lg-6">
  217. <label className="d-block mt-2"><i className="pr-2 icon-screen-desktop"></i>{t('desktop')}</label>
  218. <div className="desktop-preview d-block">
  219. {this.renderNoBreakPreview()}
  220. </div>
  221. </div>
  222. <div className="col-lg-3">
  223. <label className="d-block mt-2"><i className="pr-2 icon-screen-tablet"></i>{t('tablet')}</label>
  224. <div className="tablet-preview d-block">
  225. {this.renderNoBreakPreview()}
  226. </div>
  227. </div>
  228. <div className="col-lg-3">
  229. <label className="d-block mt-2"><i className="pr-2 icon-screen-smartphone"></i>{t('phone')}</label>
  230. <div className="mobile-preview d-block">
  231. {this.renderNoBreakPreview()}
  232. </div>
  233. </div>
  234. </div>
  235. );
  236. }
  237. }
  238. renderNoBreakPreview() {
  239. const { colsRatios } = this.state;
  240. const convertedHTML = colsRatios.map((colsRatio, i) => {
  241. const key = `grid-preview-col-${i}`;
  242. const className = `col-${colsRatio} border`;
  243. return (
  244. <div key={key} className={className}></div>
  245. );
  246. });
  247. return (
  248. <div className="row">{convertedHTML}</div>
  249. );
  250. }
  251. renderBreakPreview() {
  252. const { colsRatios } = this.state;
  253. const convertedHTML = colsRatios.map((colsRatio, i) => {
  254. const key = `grid-preview-col-${i}`;
  255. const className = 'col-12 border';
  256. return (
  257. <div key={key} className={className}></div>
  258. );
  259. });
  260. return (
  261. <div className="row">{convertedHTML}</div>
  262. );
  263. }
  264. render() {
  265. const { t } = this.props;
  266. return (
  267. <Modal isOpen={this.state.show} toggle={this.cancel} size="xl" className="grw-grid-edit-modal">
  268. <ModalHeader tag="h4" toggle={this.cancel} className="bg-primary text-light">
  269. {t('grid_edit.create_bootstrap_4_grid')}
  270. </ModalHeader>
  271. <ModalBody className="container">
  272. <div className="row">
  273. <div className="col-12">
  274. <h3 className="grw-modal-head">{t('grid_edit.grid_settings')}</h3>
  275. <form className="form-group mb-0">
  276. <div className="form-group row my-3">
  277. <label className="col-sm-3" htmlFor="gridPattern">
  278. {t('grid_edit.grid_pattern')}
  279. </label>
  280. <div className="col-sm-9">
  281. <button
  282. className="btn btn-outline-secondary dropdown-toggle"
  283. type="button"
  284. id="dropdownMenuButton"
  285. data-toggle="dropdown"
  286. aria-haspopup="true"
  287. aria-expanded="false"
  288. >
  289. {this.renderSelectedGridPattern()}
  290. </button>
  291. <div className="dropdown-menu grid-division-menu" aria-labelledby="dropdownMenuButton">
  292. {this.renderGridDivisionMenu()}
  293. </div>
  294. </div>
  295. </div>
  296. <div className="form-group row">
  297. <label className="col-sm-3" htmlFor="breakPoint">
  298. {t('grid_edit.break_point')}
  299. </label>
  300. <div className="col-sm-9">
  301. {this.renderBreakPointSetting()}
  302. </div>
  303. </div>
  304. </form>
  305. </div>
  306. </div>
  307. <h3 className="grw-modal-head">{t('preview')}</h3>
  308. {this.renderPreview()}
  309. </ModalBody>
  310. <ModalFooter className="grw-modal-footer">
  311. <div className="ml-auto">
  312. <button type="button" className="mr-2 btn btn-secondary" onClick={this.cancel}>
  313. Cancel
  314. </button>
  315. <button type="button" className="btn btn-primary" onClick={this.pasteCodedGrid}>
  316. Done
  317. </button>
  318. </div>
  319. </ModalFooter>
  320. </Modal>
  321. );
  322. }
  323. }
  324. GridEditModal.propTypes = {
  325. onSave: PropTypes.func,
  326. t: PropTypes.func.isRequired,
  327. };
  328. export default withTranslation('translation', { withRef: true })(GridEditModal);