@kaspernj/api-maker 1.0.388 → 1.0.390

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaspernj/api-maker",
3
- "version": "1.0.388",
3
+ "version": "1.0.390",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "index.js",
@@ -35,7 +35,7 @@
35
35
  "on-location-changed": ">= 1.0.13",
36
36
  "qs": ">= 6.9.3",
37
37
  "replaceall": ">= 0.1.6",
38
- "set-state-compare": "^1.0.45",
38
+ "set-state-compare": "^1.0.46",
39
39
  "spark-md5": "^3.0.2",
40
40
  "stacktrace-parser": "^0.1.10",
41
41
  "strftime": ">= 0.10.0",
package/src/form.jsx ADDED
@@ -0,0 +1,68 @@
1
+ import {createContext, memo, useContext, useMemo} from "react"
2
+ import BaseComponent from "./base-component"
3
+ import FormDataObjectizer from "form-data-objectizer"
4
+ import {Platform} from "react-native"
5
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
6
+
7
+ const FormContext = createContext(null)
8
+
9
+ class FormClass {
10
+ constructor() {
11
+ this.inputs = {}
12
+ }
13
+
14
+ asObject() {
15
+ const result = {}
16
+ const formDataObjectizer = new FormDataObjectizer()
17
+
18
+ for(const key in this.inputs) {
19
+ const value = this.inputs[key]
20
+
21
+ formDataObjectizer.treatInitial(key, value, result)
22
+ }
23
+
24
+ return result
25
+ }
26
+
27
+ setValue(name, value) {
28
+ console.log("Form", {name, value})
29
+
30
+ this.inputs[name] = value
31
+ }
32
+
33
+ setValueWithHidden(name, value) {
34
+ this.setValue(name, value)
35
+
36
+ if (Platform.OS == "web") {
37
+ return <input name={name} type="hidden" value={value !== null && value !== undefined ? value : ""} />
38
+ }
39
+ }
40
+ }
41
+
42
+ const Form = memo(shapeComponent(class Form extends BaseComponent {
43
+ render() {
44
+ const {children, setForm, ...restProps} = this.props
45
+ const form = useMemo(() => new FormClass(), [])
46
+
47
+ useMemo(() => {
48
+ if (setForm) {
49
+ setForm(form)
50
+ }
51
+ }, [setForm])
52
+
53
+ return (
54
+ <FormContext.Provider value={form}>
55
+ {Platform.OS == "web" &&
56
+ <form {...restProps}>
57
+ {children}
58
+ </form>
59
+ }
60
+ {Platform.OS != "web" && this.props.children}
61
+ </FormContext.Provider>
62
+ )
63
+ }
64
+ }))
65
+
66
+ const useForm = () => useContext(FormContext)
67
+
68
+ export {Form, FormContext, useForm}
@@ -1,7 +1,10 @@
1
+ import BaseComponent from "../base-component"
1
2
  import {Input as ApiMakerInput} from "@kaspernj/api-maker/src/inputs/input"
2
3
  import {Checkbox} from "./checkbox"
4
+ import {memo} from "react"
5
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
3
6
 
4
- export default class ApiMakerInputsAttachment extends BaseComponent {
7
+ export default memo(shapeComponent(class ApiMakerInputsAttachment extends BaseComponent {
5
8
  static propTypes = {
6
9
  className: PropTypes.string,
7
10
  model: PropTypes.object.isRequired,
@@ -9,8 +12,10 @@ export default class ApiMakerInputsAttachment extends BaseComponent {
9
12
  purgeName: PropTypes.string
10
13
  }
11
14
 
12
- state = {
13
- purgeChecked: false
15
+ setup() {
16
+ this.useStates({
17
+ purgeChecked: false
18
+ })
14
19
  }
15
20
 
16
21
  render() {
@@ -91,4 +96,4 @@ export default class ApiMakerInputsAttachment extends BaseComponent {
91
96
 
92
97
  if (this.props.onPurgeChanged) this.props.onPurgeChanged(e)
93
98
  }
94
- }
99
+ }))
@@ -1,11 +1,14 @@
1
1
  import AutoSubmit from "./auto-submit.mjs"
2
+ import BaseComponent from "../base-component"
2
3
  import {digg, digs} from "diggerize"
3
4
  import EventUpdated from "../event-updated"
4
5
  import inputWrapper from "./input-wrapper"
5
6
  import PropTypes from "prop-types"
6
- import React from "react"
7
+ import {memo} from "react"
8
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
9
+ import {useForm} from "../form"
7
10
 
8
- class ApiMakerInputsCheckbox extends React.PureComponent {
11
+ const ApiMakerInputsCheckbox = memo(shapeComponent(class ApiMakerInputsCheckbox extends BaseComponent {
9
12
  static defaultProps = {
10
13
  autoRefresh: false,
11
14
  autoSubmit: false,
@@ -28,6 +31,10 @@ class ApiMakerInputsCheckbox extends React.PureComponent {
28
31
  zeroInput: PropTypes.bool
29
32
  }
30
33
 
34
+ setup() {
35
+ this.form = useForm()
36
+ }
37
+
31
38
  render () {
32
39
  const {
33
40
  attribute,
@@ -69,9 +76,11 @@ class ApiMakerInputsCheckbox extends React.PureComponent {
69
76
  }
70
77
 
71
78
  onChanged = (...args) => {
72
- const {attribute, autoSubmit, model, onChange} = this.props
79
+ const {form} = this.tt
80
+ const {attribute, autoSubmit, model, name, onChange} = this.props
73
81
 
74
82
  if (attribute && autoSubmit && model) new AutoSubmit({component: this}).autoSubmit()
83
+ if (form && name) form.setValue(name, args[0].target.checked)
75
84
  if (onChange) onChange(...args)
76
85
  }
77
86
 
@@ -92,7 +101,7 @@ class ApiMakerInputsCheckbox extends React.PureComponent {
92
101
  inputRef.current.checked = newValue
93
102
  }
94
103
  }
95
- }
104
+ }))
96
105
 
97
106
  export {ApiMakerInputsCheckbox as Checkbox}
98
107
  export default inputWrapper(ApiMakerInputsCheckbox, {type: "checkbox"})
@@ -1,3 +1,4 @@
1
+ import BaseComponent from "../base-component"
1
2
  import classNames from "classnames"
2
3
  import {digs} from "diggerize"
3
4
  import inputWrapper from "./input-wrapper"
@@ -5,9 +6,10 @@ import * as inflection from "inflection"
5
6
  import InvalidFeedback from "../bootstrap/invalid-feedback"
6
7
  import PropTypes from "prop-types"
7
8
  import propTypesExact from "prop-types-exact"
8
- import React from "react"
9
+ import {memo} from "react"
10
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
9
11
 
10
- class ApiMakerInputsCheckboxes extends React.PureComponent {
12
+ const ApiMakerInputsCheckboxes = memo(shapeComponent(class ApiMakerInputsCheckboxes extends BaseComponent {
11
13
  static propTypes = propTypesExact({
12
14
  attribute: PropTypes.string,
13
15
  defaultValue: PropTypes.array,
@@ -108,6 +110,6 @@ class ApiMakerInputsCheckboxes extends React.PureComponent {
108
110
  </div>
109
111
  )
110
112
  }
111
- }
113
+ }))
112
114
 
113
115
  export default inputWrapper(ApiMakerInputsCheckboxes)
@@ -1,4 +1,5 @@
1
1
  import AutoSubmit from "./auto-submit.mjs"
2
+ import BaseComponent from "../base-component"
2
3
  import {dig, digg, digs} from "diggerize"
3
4
  import EventUpdated from "../event-updated"
4
5
  import inputWrapper from "./input-wrapper"
@@ -6,10 +7,11 @@ import Money from "./money"
6
7
  import PropTypes from "prop-types"
7
8
  import {memo, useRef} from "react"
8
9
  import replaceall from "replaceall"
9
- import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
10
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
10
11
  import strftime from "strftime"
12
+ import {useForm} from "../form"
11
13
 
12
- const ApiMakerInputsInput = memo(shapeComponent(class ApiMakerInputsInput extends ShapeComponent {
14
+ const ApiMakerInputsInput = memo(shapeComponent(class ApiMakerInputsInput extends BaseComponent {
13
15
  static defaultProps = {
14
16
  autoRefresh: false,
15
17
  autoSubmit: false,
@@ -32,6 +34,7 @@ const ApiMakerInputsInput = memo(shapeComponent(class ApiMakerInputsInput extend
32
34
  }
33
35
 
34
36
  setup() {
37
+ this.form = useForm()
35
38
  this.visibleInputRef = useRef()
36
39
 
37
40
  this.useStates({
@@ -204,13 +207,15 @@ const ApiMakerInputsInput = memo(shapeComponent(class ApiMakerInputsInput extend
204
207
  }
205
208
 
206
209
  onInputChanged = (e) => {
207
- const {attribute, autoSubmit, inputProps, model, onChange} = this.props
210
+ const {form} = this.tt
211
+ const {attribute, autoSubmit, inputProps, model, name, onChange} = this.props
208
212
  const {localizedNumber} = digs(this.props, "localizedNumber")
209
213
 
210
214
  if (localizedNumber) this.inputReference().current.value = this.actualValue(digg(e, "target"))
211
215
 
212
216
  if (attribute && autoSubmit && model) this.delayAutoSubmit()
213
217
  if (digg(inputProps, "type") == "file") this.setState({blankInputName: this.getBlankInputName()})
218
+ if (form && name) form.setValue(name, e.target.value)
214
219
  if (onChange) onChange(e)
215
220
  }
216
221
 
@@ -1,9 +1,11 @@
1
- import {dig} from "diggerize"
1
+ import BaseComponent from "../base-component"
2
2
  import inputWrapper from "./input-wrapper"
3
3
  import PropTypes from "prop-types"
4
- import React from "react"
4
+ import {memo} from "react"
5
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
6
+ import {useForm} from "../form"
5
7
 
6
- class ApiMakerInputsSelect extends React.PureComponent {
8
+ const ApiMakerInputsSelect = memo(shapeComponent(class ApiMakerInputsSelect extends BaseComponent {
7
9
  static propTypes = {
8
10
  attribute: PropTypes.string,
9
11
  children: PropTypes.node,
@@ -13,10 +15,15 @@ class ApiMakerInputsSelect extends React.PureComponent {
13
15
  inputProps: PropTypes.object.isRequired,
14
16
  model: PropTypes.object,
15
17
  name: PropTypes.string,
18
+ onChange: PropTypes.func,
16
19
  options: PropTypes.array,
17
20
  wrapperOpts: PropTypes.object.isRequired
18
21
  }
19
22
 
23
+ setup() {
24
+ this.form = useForm()
25
+ }
26
+
20
27
  render () {
21
28
  const {
22
29
  attribute,
@@ -28,13 +35,14 @@ class ApiMakerInputsSelect extends React.PureComponent {
28
35
  inputRef,
29
36
  model,
30
37
  name,
38
+ onChange,
31
39
  options,
32
40
  wrapperOpts,
33
41
  ...restProps
34
42
  } = this.props
35
43
 
36
44
  return (
37
- <select {...inputProps} {...restProps}>
45
+ <select onChange={this.tt.onChange} {...inputProps} {...restProps}>
38
46
  {this.includeBlank() &&
39
47
  <option data-include-blank="true">
40
48
  {typeof includeBlank != "boolean" ? includeBlank : null}
@@ -50,6 +58,14 @@ class ApiMakerInputsSelect extends React.PureComponent {
50
58
  )
51
59
  }
52
60
 
61
+ onChange = (e) => {
62
+ const {form} = this.tt
63
+ const {name, onChange} = this.props
64
+
65
+ if (form && name) form.setValue(name, e.target.value)
66
+ if (onChange) onChange(e)
67
+ }
68
+
53
69
  optionKey (option) {
54
70
  if (Array.isArray(option)) {
55
71
  return `select-option-${option[1]}`
@@ -81,7 +97,7 @@ class ApiMakerInputsSelect extends React.PureComponent {
81
97
  return false
82
98
  }
83
99
  }
84
- }
100
+ }))
85
101
 
86
102
  export {ApiMakerInputsSelect as Select}
87
103
  export default inputWrapper(ApiMakerInputsSelect)
@@ -49,12 +49,12 @@ export default class ApiMakerSuperAdminConfigReader {
49
49
  const {modelConfig} = digs(this, "modelConfig")
50
50
 
51
51
  if (modelConfig?.table?.columns) {
52
- return modelConfig.table.columns()
52
+ return {
53
+ columns: modelConfig.table.columns()
54
+ }
55
+ } else {
56
+ return this.defaultTableColumns()
53
57
  }
54
-
55
- const {columns} = this.defaultTableColumns()
56
-
57
- return columns
58
58
  }
59
59
 
60
60
  defaultTableColumns() {
@@ -1,35 +1,57 @@
1
1
  import BaseComponent from "../../base-component"
2
+ import {FormContext} from "../../form"
2
3
  import {memo} from "react"
3
4
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
4
5
 
5
6
  export default memo(shapeComponent(class EditAttributeContent extends BaseComponent {
7
+ setup() {
8
+ const {inputs, name} = this.p
9
+
10
+ this.form = useContext(FormContext)
11
+ this.useStates({
12
+ value: () => this.defaultValue()
13
+ })
14
+
15
+ useMemo(() => {
16
+ inputs[name] = this.s.value
17
+
18
+ if (this.form) {
19
+ this.form.setValue(name, this.s.value)
20
+ }
21
+ }, [])
22
+ }
23
+
6
24
  render() {
7
- const {attribute, id, inputs, model, name} = this.props
25
+ const {attribute, id, model} = this.props
8
26
 
9
27
  if (!(attribute.attribute in model)) {
10
28
  throw new Error(`${attribute.attribute} isn't set on the resource ${model.modelClassData().name}`)
11
29
  }
12
30
 
13
- const defaultValue = useCallback(() => model[attribute.attribute]() || "")
14
- const [value, setValue] = useState(() => defaultValue())
15
- const onChangeValue = useCallback((newValue) => {
16
- inputs[name] = newValue
17
- setValue(newValue)
18
- })
19
- useMemo(() => {
20
- inputs[name] = value
21
- }, [])
22
-
23
- const contentArgs = () => ({
31
+ const contentArgs = useMemo(() => ({
24
32
  inputProps: {
25
33
  attribute: attribute.attribute,
26
- defaultValue: defaultValue(),
34
+ defaultValue: this.defaultValue(),
27
35
  id,
28
36
  model
29
37
  },
30
- onChangeValue
31
- })
38
+ onChangeValue: this.tt.onChangeValue
39
+ }), [attribute.attribute, id, model])
40
+
41
+ return attribute.content(contentArgs)
42
+ }
43
+
44
+ defaultValue = () => this.p.model[this.p.attribute.attribute]() || ""
45
+
46
+ onChangeValue = (newValue) => {
47
+ const {inputs, name} = this.p
48
+
49
+ inputs[name] = newValue
50
+
51
+ if (this.form) {
52
+ this.form.setValue(name, newValue)
53
+ }
32
54
 
33
- return attribute.content(contentArgs())
55
+ this.setState({value: newValue})
34
56
  }
35
57
  }))
@@ -1,4 +1,5 @@
1
1
  import BaseComponent from "../../base-component"
2
+ import {useForm} from "../../form"
2
3
  import PropTypes from "prop-types"
3
4
  import propTypesExact from "prop-types-exact"
4
5
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
@@ -14,12 +15,17 @@ export default memo(shapeComponent(class EditAttributeInput extends BaseComponen
14
15
  setup() {
15
16
  const {inputs, name} = this.p
16
17
 
18
+ this.form = useForm()
17
19
  this.useStates({
18
20
  value: this.defaultValue()
19
21
  })
20
22
 
21
23
  useMemo(() => {
22
24
  inputs[name] = this.s.value
25
+
26
+ if (this.form) {
27
+ this.form.setValue(name, this.s.value)
28
+ }
23
29
  }, [])
24
30
  }
25
31
 
@@ -56,6 +62,11 @@ export default memo(shapeComponent(class EditAttributeInput extends BaseComponen
56
62
  const {inputs, name} = this.p
57
63
 
58
64
  inputs[name] = newValue
65
+
66
+ if (this.form) {
67
+ this.form.setValue(name, newValue)
68
+ }
69
+
59
70
  this.setState({value: newValue})
60
71
  }
61
72
  }))
@@ -1,9 +1,10 @@
1
+ import {Pressable, Text, View} from "react-native"
1
2
  import BaseComponent from "../base-component"
2
3
  import ConfigReader from "./config-reader.jsx"
3
4
  import {digg} from "diggerize"
4
5
  import EditAttribute from "./edit-page/edit-attribute"
6
+ import {Form} from "../form"
5
7
  import * as inflection from "inflection"
6
- import {Pressable, Text, View} from "react-native"
7
8
  import Locales from "shared/locales"
8
9
  import {memo} from "react"
9
10
  import PropTypes from "prop-types"
@@ -50,7 +51,8 @@ export default memo(shapeComponent(class ApiMakerSuperAdminEditPage extends Base
50
51
  const useModelResult = useModel(modelClass, {
51
52
  cacheArgs: [currentUser?.id()],
52
53
  loadByQueryParam: (props) => props.queryParams.model_id,
53
- newIfNoId: true,
54
+ newIfNoId: this.configReader.modelConfig?.edit?.newIfNoId || true,
55
+ preload: this.configReader.modelConfig?.edit?.preload,
54
56
  select: selectedAttributes
55
57
  })
56
58
 
@@ -61,6 +63,7 @@ export default memo(shapeComponent(class ApiMakerSuperAdminEditPage extends Base
61
63
  this.modelId = queryParams.model_id
62
64
  this.modelArgs = {}
63
65
  this.modelArgs[modelIdVarName] = this.modelId
66
+ this.useStates({form: null})
64
67
  }
65
68
 
66
69
  render() {
@@ -70,27 +73,29 @@ export default memo(shapeComponent(class ApiMakerSuperAdminEditPage extends Base
70
73
 
71
74
  return (
72
75
  <View dataSet={{class: "super-admin--edit-page"}}>
73
- {model && attributes?.map((attribute) =>
74
- <EditAttribute attribute={attribute} inputs={this.inputs} key={attribute.attribute} model={model} modelClass={modelClass} />
75
- )}
76
- {extraContent && extraContent(modelArgs)}
77
- <Pressable
78
- dataSet={{class: "submit-button"}}
79
- onPress={this.tt.onSubmit}
80
- style={{
81
- paddingTop: 18,
82
- paddingRight: 24,
83
- paddingBottom: 18,
84
- paddingLeft: 24,
85
- borderRadius: 10,
86
- backgroundColor: "#4c93ff",
87
- marginTop: 10
88
- }}
89
- >
90
- <Text style={{color: "#fff"}}>
91
- Submit
92
- </Text>
93
- </Pressable>
76
+ <Form setForm={this.setStates.form}>
77
+ {model && attributes?.map((attribute) =>
78
+ <EditAttribute attribute={attribute} inputs={this.inputs} key={attribute.attribute} model={model} modelClass={modelClass} />
79
+ )}
80
+ {extraContent && extraContent(modelArgs)}
81
+ <Pressable
82
+ dataSet={{class: "submit-button"}}
83
+ onPress={this.tt.onSubmit}
84
+ style={{
85
+ paddingTop: 18,
86
+ paddingRight: 24,
87
+ paddingBottom: 18,
88
+ paddingLeft: 24,
89
+ borderRadius: 10,
90
+ backgroundColor: "#4c93ff",
91
+ marginTop: 10
92
+ }}
93
+ >
94
+ <Text style={{color: "#fff"}}>
95
+ Submit
96
+ </Text>
97
+ </Pressable>
98
+ </Form>
94
99
  </View>
95
100
  )
96
101
  }
@@ -98,8 +103,14 @@ export default memo(shapeComponent(class ApiMakerSuperAdminEditPage extends Base
98
103
  onSubmit = async () => {
99
104
  try {
100
105
  const {inputs, model} = this.tt
106
+ const {form} = this.s
107
+
108
+ const formObject = form.asObject()
109
+ const allInputs = Object.assign({}, inputs, formObject)
110
+
111
+ console.log({allInputs})
101
112
 
102
- model.assignAttributes(inputs)
113
+ model.assignAttributes(allInputs)
103
114
  await model.save(this.inputs)
104
115
  Params.changeParams({mode: undefined, model_id: model.id()})
105
116
  } catch (error) {
@@ -3,6 +3,7 @@ import {memo} from "react"
3
3
  import ModelClassTable from "./model-class-table"
4
4
  import PropTypes from "prop-types"
5
5
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
6
+ import {View} from "react-native"
6
7
 
7
8
  export default memo(shapeComponent(class ApiMakerSuperAdminIndexPage extends BaseComponent {
8
9
  static propTypes = {
@@ -13,9 +14,9 @@ export default memo(shapeComponent(class ApiMakerSuperAdminIndexPage extends Bas
13
14
  const {modelClass} = this.props
14
15
 
15
16
  return (
16
- <div className="super-admin--index-page">
17
+ <View dataSet={{component: "super-admin--index-page"}}>
17
18
  <ModelClassTable modelClass={modelClass} />
18
- </div>
19
+ </View>
19
20
  )
20
21
  }
21
22
  }))
@@ -1,10 +1,12 @@
1
1
  import "./style"
2
2
  import BaseComponent from "../../../base-component"
3
- import EventListener from "../../../event-listener"
4
3
  import {memo, useRef} from "react"
5
4
  import PropTypes from "prop-types"
6
5
  import PropTypesExact from "prop-types-exact"
7
6
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
7
+ import {Text, View} from "react-native"
8
+ import useBreakpoint from "../../../use-breakpoint"
9
+ import useEventListener from "../../../use-event-listener"
8
10
 
9
11
  export default memo(shapeComponent(class ApiMakerSuperAdminLayoutHeader extends BaseComponent {
10
12
  static propTypes = PropTypesExact({
@@ -14,27 +16,93 @@ export default memo(shapeComponent(class ApiMakerSuperAdminLayoutHeader extends
14
16
  })
15
17
 
16
18
  setup() {
19
+ const {breakpoint} = useBreakpoint()
20
+
17
21
  this.headerActionsRef = useRef()
22
+ this.setInstance({breakpoint})
18
23
  this.useStates({
19
24
  headerActionsActive: false
20
25
  })
26
+
27
+ useEventListener(window, "mouseup", this.tt.onWindowMouseUp)
21
28
  }
22
29
 
23
30
  render() {
31
+ const {breakpoint} = this.tt
24
32
  const {actions, onTriggerMenu, title} = this.props
25
33
 
34
+ const headerStyle = {
35
+ display: "flex",
36
+ flexDirection: "row",
37
+ alignItems: "center",
38
+ zIndex: 9,
39
+ height: 100,
40
+ paddingRight: 30,
41
+ paddingLeft: 30,
42
+ backgroundColor: "#fff"
43
+ }
44
+
45
+ const headerActionsContainerStyle = {}
46
+ const headerActionsStyle = {}
47
+
48
+ if (breakpoint == "xs" || breakpoint == "sm") {
49
+ headerStyle.position = "absolute"
50
+ headerStyle.width = "100%"
51
+
52
+ Object.assign(headerActionsContainerStyle, {
53
+ position: "fixed",
54
+ top: 0,
55
+ left: 0,
56
+
57
+ display: "flex",
58
+ width: "100vw",
59
+ height: "100vh",
60
+ alignItems: "center",
61
+ justifyContent: "center",
62
+
63
+ background: "rgba(#000, .8)"
64
+ })
65
+
66
+ if (!this.s.headerActionsActive) {
67
+ headerActionsContainerStyle.display = "none"
68
+ }
69
+
70
+ Object.assign(headerActionsStyle, {
71
+ minWidth: "80vw",
72
+ maxWidth: "100vw",
73
+ backgroundColor: "#fff"
74
+ })
75
+ } else if (breakpoint == "md") {
76
+ headerStyle.position = "fixed"
77
+ headerStyle.left = 250
78
+ headerStyle.width = "calc(100% - 250px)"
79
+ } else if (breakpoint == "lg" || breakpoint == "xl" || breakpoint == "xxl") {
80
+ headerStyle.position = "fixed"
81
+ headerStyle.left = 290
82
+ headerStyle.width = "calc(100% - 290px)"
83
+ }
84
+
85
+ if (breakpoint == "md" || breakpoint == "lg" || breakpoint == "xl" || breakpoint == "xxl") {
86
+ headerActionsContainerStyle.marginLeft = "auto"
87
+ }
88
+
26
89
  return (
27
- <div className="components--admin--layout--header">
28
- <EventListener event="mouseup" onCalled={this.tt.onWindowMouseUp} target={window} />
29
- <div className="header-title-container">
30
- {title}
31
- </div>
90
+ <View dataSet={{component: "super-admin--layout--header"}} style={headerStyle}>
91
+ <View dataSet={{class: "header-title-container"}}>
92
+ <Text style={{color: "#282a33", fontSize: 22}}>
93
+ {title}
94
+ </Text>
95
+ </View>
32
96
  {actions &&
33
- <div className="header-actions-container" data-active={this.s.headerActionsActive}>
34
- <div className="header-actions" ref={this.tt.headerActionsRef}>
97
+ <View dataSet={{active: this.s.headerActionsActive, class: "header-actions-container"}} style={headerActionsContainerStyle}>
98
+ <View
99
+ dataSet={{class: "header-actions"}}
100
+ ref={this.tt.headerActionsRef}
101
+ style={headerActionsStyle}
102
+ >
35
103
  {actions}
36
- </div>
37
- </div>
104
+ </View>
105
+ </View>
38
106
  }
39
107
  <div className="burger-menu-container">
40
108
  {actions &&
@@ -46,7 +114,7 @@ export default memo(shapeComponent(class ApiMakerSuperAdminLayoutHeader extends
46
114
  <i className="fa fa-bars" />
47
115
  </a>
48
116
  </div>
49
- </div>
117
+ </View>
50
118
  )
51
119
  }
52
120
 
@@ -1,42 +1,8 @@
1
1
  @import "@kaspernj/api-maker/src/super-admin/stylesheets/variables";
2
2
 
3
- .components--admin--layout--header {
4
- top: 0;
5
- display: flex;
6
- height: 100px;
7
- align-items: center;
8
- padding-right: 30px;
9
- padding-left: 30px;
10
- background: #fff;
11
- color: #282a33;
12
-
3
+ [data-component="super-admin--layout--header"] {
13
4
  @media (max-width: $sm-to) {
14
- position: absolute;
15
- width: 100%;
16
-
17
- .header-actions-container {
18
- position: fixed;
19
- top: 0;
20
- left: 0;
21
-
22
- display: flex;
23
- width: 100vw;
24
- height: 100vh;
25
- align-items: center;
26
- justify-content: center;
27
-
28
- background: rgba(#000, .8);
29
-
30
- &[data-active="false"] {
31
- display: none;
32
- }
33
- }
34
-
35
- .header-actions {
36
- min-width: 80vw;
37
- max-width: 100vw;
38
- background: #fff;
39
-
5
+ [data-class="header-actions"] {
40
6
  .action-button {
41
7
  display: block;
42
8
  padding: 11px;
@@ -63,15 +29,7 @@
63
29
  }
64
30
 
65
31
  @media (min-width: $md-from) {
66
- position: fixed;
67
- left: 250px;
68
- width: calc(100% - 250px);
69
-
70
- .header-actions-container {
71
- margin-left: auto;
72
- }
73
-
74
- .header-actions {
32
+ [data-class="header-actions"] {
75
33
  .action-button {
76
34
  display: inline-block;
77
35
  padding: 7px 10px;
@@ -89,11 +47,6 @@
89
47
  }
90
48
  }
91
49
 
92
- @media (min-width: $lg-from) {
93
- left: 290px;
94
- width: calc(100% - 290px);
95
- }
96
-
97
50
  .burger-menu-container {
98
51
  @media (max-width: $sm-to) {
99
52
  margin-left: auto;
@@ -117,8 +70,4 @@
117
70
  color: #1b1c1e;
118
71
  }
119
72
  }
120
-
121
- .header-title-container {
122
- font-size: 22px;
123
- }
124
73
  }
@@ -7,10 +7,11 @@ import Header from "./header"
7
7
  import Menu from "./menu"
8
8
  import PropTypes from "prop-types"
9
9
  import PropTypesExact from "prop-types-exact"
10
- import {memo, useCallback, useMemo} from "react"
10
+ import {memo, useMemo} from "react"
11
11
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
12
12
  import useCurrentUser from "../../use-current-user"
13
- import useShape from "set-state-compare/src/use-shape.js"
13
+ import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
14
+ import {View} from "react-native"
14
15
 
15
16
  const NoAccess = React.lazy(() => import("./no-access"))
16
17
 
@@ -27,7 +28,21 @@ export default memo(shapeComponent(class ApiMakerSuperAdminLayout extends BaseCo
27
28
  headerTitle: PropTypes.string
28
29
  })
29
30
 
31
+ setup() {
32
+ const currentUser = useCurrentUser()
33
+ const {locale, t} = useI18n({namespace: "js.api_maker.super_admin.layout"})
34
+
35
+ this.useStates({menuTriggered: false})
36
+ this.setInstance({currentUser, t})
37
+
38
+ useMemo(() => {
39
+ CommandsPool.current().globalRequestData.layout = "admin"
40
+ CommandsPool.current().globalRequestData.locale = locale
41
+ }, [I18n.locale])
42
+ }
43
+
30
44
  render() {
45
+ const {currentUser, t} = this.tt
31
46
  const {
32
47
  actions,
33
48
  active,
@@ -39,14 +54,6 @@ export default memo(shapeComponent(class ApiMakerSuperAdminLayout extends BaseCo
39
54
  menu,
40
55
  ...restProps
41
56
  } = this.props
42
- const s = useShape()
43
- const currentUser = useCurrentUser()
44
-
45
- useMemo(() => {
46
- CommandsPool.current().globalRequestData.layout = "admin"
47
- CommandsPool.current().globalRequestData.locale = I18n.locale
48
- }, [I18n.locale])
49
-
50
57
  const headTitle = headTitle || headerTitle
51
58
 
52
59
  if (headTitle) {
@@ -55,38 +62,32 @@ export default memo(shapeComponent(class ApiMakerSuperAdminLayout extends BaseCo
55
62
  document.title = "Wooftech"
56
63
  }
57
64
 
58
- const setMenuTriggered = s.useState("menuTriggered", false)
59
65
  const noAccess = !currentUser
60
- const onRequestMenuClose = useCallback(() => setMenuTriggered(false), [])
61
- const onTriggerMenu = useCallback((e) => {
62
- e.preventDefault()
63
- setMenuTriggered(!s.state.menuTriggered)
64
- }, [])
65
66
 
66
67
  return (
67
- <div className={classNames("components--admin--layout", className)} data-menu-triggered={s.state.menuTriggered} {...restProps}>
68
+ <View dataSet={{component: "super-admin--layout", class: className, menuTriggered: this.s.menuTriggered}} {...restProps}>
68
69
  <Menu
69
70
  active={active}
70
71
  noAccess={noAccess}
71
- onRequestMenuClose={onRequestMenuClose}
72
- triggered={s.state.menuTriggered}
72
+ onRequestMenuClose={this.tt.onRequestMenuClose}
73
+ triggered={this.s.menuTriggered}
73
74
  />
74
- <Header actions={actions} onTriggerMenu={onTriggerMenu} title={headerTitle} />
75
- <div className="app-layout-content-container">
75
+ <Header actions={actions} onTriggerMenu={this.tt.onTriggerMenu} title={headerTitle} />
76
+ <View dataSet={{class: "app-layout-content-container"}}>
76
77
  {noAccess &&
77
78
  <>
78
79
  <NoAccess />
79
80
  {currentUser &&
80
81
  <>
81
82
  <div className="mb-4">
82
- {I18n.t("js.api_maker.super_admin.layout.try_signing_out_and_in_with_a_different_user", {defaultValue: "Try signing in with a different user."})}
83
+ {t(".try_signing_out_and_in_with_a_different_user", {defaultValue: "Try signing in with a different user."})}
83
84
  </div>
84
85
  </>
85
86
  }
86
87
  {!currentUser &&
87
88
  <>
88
89
  <div className="mb-4">
89
- {I18n.t("js.api_maker.super_admin.layout.try_signing_in", {defaultValue: "Try signing in."})}
90
+ {t(".try_signing_in", {defaultValue: "Try signing in."})}
90
91
  </div>
91
92
  {config.signInContent()}
92
93
  </>
@@ -94,8 +95,14 @@ export default memo(shapeComponent(class ApiMakerSuperAdminLayout extends BaseCo
94
95
  </>
95
96
  }
96
97
  {!noAccess && children}
97
- </div>
98
- </div>
98
+ </View>
99
+ </View>
99
100
  )
100
101
  }
102
+
103
+ onRequestMenuClose = () => this.setState({menuTriggered: false})
104
+ onTriggerMenu = (e) => {
105
+ e.preventDefault()
106
+ setMenuTriggered(!this.s.menuTriggered)
107
+ }
101
108
  }))
@@ -8,6 +8,8 @@ import PropTypes from "prop-types"
8
8
  import PropTypesExact from "prop-types-exact"
9
9
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
10
10
  import useCurrentUser from "../../../use-current-user"
11
+ import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
12
+ import {View} from "react-native"
11
13
 
12
14
  export default memo(shapeComponent(class ComponentsAdminLayoutMenu extends BaseComponent {
13
15
  static propTypes = PropTypesExact({
@@ -17,13 +19,19 @@ export default memo(shapeComponent(class ComponentsAdminLayoutMenu extends BaseC
17
19
  triggered: PropTypes.bool.isRequired
18
20
  })
19
21
 
22
+ setup() {
23
+ const {t} = useI18n({namespace: "js.api_maker.super_admin.layout.menu"})
24
+ const currentUser = useCurrentUser()
25
+
26
+ this.setInstance({currentUser, t})
27
+ }
28
+
20
29
  render() {
30
+ const {currentUser, t} = this.tt
21
31
  const {active, noAccess, triggered} = this.props
22
- const currentUser = useCurrentUser()
23
- const rootRef = useRef()
24
32
 
25
33
  return (
26
- <div className="components--admin--layout--menu" data-triggered={triggered} ref={rootRef}>
34
+ <View dataSet={{component: "super-admin--layout--menu", triggered}}>
27
35
  <div className="menu-logo">
28
36
  <Link className="menu-logo-link" to={Params.withParams({})}>
29
37
  Admin
@@ -52,12 +60,12 @@ export default memo(shapeComponent(class ComponentsAdminLayoutMenu extends BaseC
52
60
  active
53
61
  className="sign-out-menu-item"
54
62
  icon="sign-out-alt"
55
- label={I18n.t("js.api_maker.super_admin.layout.menu.sign_out", {defaultValue: "Sign out"})}
63
+ label={t(".sign_out", {defaultValue: "Sign out"})}
56
64
  onClick={this.tt.onSignOutClicked}
57
65
  />
58
66
  }
59
67
  </div>
60
- </div>
68
+ </View>
61
69
  )
62
70
  }
63
71
 
@@ -66,7 +74,7 @@ export default memo(shapeComponent(class ComponentsAdminLayoutMenu extends BaseC
66
74
 
67
75
  try {
68
76
  await Devise.signOut()
69
- FlashMessage.success(I18n.t("js.api_maker.super_admin.layout.menu.you_have_been_signed_out", {defaultValue: "You have been signed out"}))
77
+ FlashMessage.success(this.t(".you_have_been_signed_out", {defaultValue: "You have been signed out"}))
70
78
  } catch (error) {
71
79
  FlashMessage.errorResponse(error)
72
80
  }
@@ -1,6 +1,6 @@
1
1
  @import "@kaspernj/api-maker/src/super-admin/stylesheets/variables";
2
2
 
3
- .components--admin--layout--menu {
3
+ [data-component="super-admin--layout--menu"] {
4
4
  position: fixed;
5
5
  z-index: 9;
6
6
  overflow-y: auto;
@@ -2,18 +2,23 @@ import BaseComponent from "../../base-component"
2
2
  import {memo} from "react"
3
3
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
4
4
  import useCurrentUser from "../../use-current-user"
5
+ import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
6
+ import {View} from "react-native"
5
7
 
6
8
  export default memo(shapeComponent(class ComponentsAdminLayoutNoAccess extends BaseComponent {
7
9
  render() {
8
10
  const currentUser = useCurrentUser()
11
+ const {t} = useI18n({namespace: "js.api_maker.super_admin.layout.no_access"})
9
12
 
10
13
  return (
11
- <div
12
- className="components--admin--layout-no-access"
13
- data-user-roles={currentUser?.userRoles()?.loaded()?.map((userRole) => userRole.role()?.identifier()).join(", ")}
14
+ <View
15
+ dataSet={{
16
+ component: "super-admin--layout--no-access",
17
+ userRoles: currentUser?.userRoles()?.loaded()?.map((userRole) => userRole.role()?.identifier()).join(", ")
18
+ }}
14
19
  >
15
- {I18n.t("js.api_maker.super_admin.layout.no_access.you_dont_have_no_access_to_this_page", {defaultValue: "You don't have access to this page."})}
16
- </div>
20
+ {t(".you_dont_have_no_access_to_this_page", {defaultValue: "You don't have access to this page."})}
21
+ </View>
17
22
  )
18
23
  }
19
24
  }))
@@ -1,12 +1,12 @@
1
1
  @import "@kaspernj/api-maker/src/super-admin/stylesheets/variables";
2
2
 
3
- .components--admin--layout {
3
+ [data-component="super-admin--layout"] {
4
4
  width: 100%;
5
5
  min-height: 100vh;
6
6
  background: #fff;
7
7
  color: #000;
8
8
 
9
- .app-layout-content-container {
9
+ [data-class="app-layout-content-container"] {
10
10
  min-height: 100vh;
11
11
  background: #f7f7f7;
12
12
 
@@ -23,6 +23,8 @@ export default memo(shapeComponent(class ApiMakerSuperAdminModelClassTable exten
23
23
  const tableConfig = configReader.modelConfig?.table
24
24
  const tableProps = {}
25
25
 
26
+ if (!columns) throw new Error("No columns given")
27
+
26
28
  if (tableConfig?.query) tableProps.collection = tableConfig.query
27
29
 
28
30
  return (
@@ -5,7 +5,9 @@ import PropTypesExact from "prop-types-exact"
5
5
  import {memo} from "react"
6
6
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
7
7
  import ShowReflectionLink from "./show-reflection-link"
8
+ import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
8
9
  import useQueryParams from "on-location-changed/src/use-query-params"
10
+ import {View} from "react-native"
9
11
 
10
12
  export default memo(shapeComponent(class ApiMakerSuperAdminShowNav extends BaseComponent {
11
13
  static propTypes = PropTypesExact({
@@ -14,23 +16,24 @@ export default memo(shapeComponent(class ApiMakerSuperAdminShowNav extends BaseC
14
16
  })
15
17
 
16
18
  render() {
19
+ const {t} = useI18n({namespace: "js.api_maker.suprt_admin.show_reflection_page"})
17
20
  const {model, modelClass} = this.props
18
21
  const queryParams = useQueryParams()
19
22
  const reflections = modelClass.reflections()
20
23
 
21
24
  return (
22
- <div>
23
- <div>
25
+ <View dataSet={{component: "super-admin--show-nav"}}>
26
+ <View>
24
27
  <Link to={Params.withParams({model: modelClass.modelClassData().name, model_id: queryParams.model_id})}>
25
- {I18n.t("js.api_maker.suprt_admin.show_reflection_page.general", {defaultValue: "General"})}
28
+ {t(".general", {defaultValue: "General"})}
26
29
  </Link>
27
- </div>
30
+ </View>
28
31
  {model && reflections.filter((reflection) => reflection.macro() == "has_many").map((reflection) =>
29
- <div key={reflection.name()}>
32
+ <View key={reflection.name()}>
30
33
  <ShowReflectionLink model={model} modelClass={modelClass} reflection={reflection} />
31
- </div>
34
+ </View>
32
35
  )}
33
- </div>
36
+ </View>
34
37
  )
35
38
  }
36
39
  }))
@@ -9,6 +9,7 @@ import {memo, useMemo} from "react"
9
9
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
10
10
  import ShowNav from "../show-nav"
11
11
  import useModel from "../../use-model"
12
+ import {View} from "react-native"
12
13
 
13
14
  const AttributePresenter = memo(({attribute, model, modelArgs}) => {
14
15
  const attributeRowProps = {
@@ -63,7 +64,9 @@ export default memo(shapeComponent(class ApiMakerSuperAdminShowPage extends Base
63
64
 
64
65
  // Select all attributes selected by default because they will be shown by default
65
66
  for (const attribute of modelClass.attributes()) {
66
- if (attribute.isSelectedByDefault() && !modelClassSelect.includes(attribute.name())) modelClassSelect.push(attribute.name())
67
+ if ((attribute.isSelectedByDefault() || attribute.name() == "name") && !modelClassSelect.includes(attribute.name())) {
68
+ modelClassSelect.push(attribute.name())
69
+ }
67
70
  }
68
71
 
69
72
  for (const reflection of modelClass.reflections()) {
@@ -112,7 +115,7 @@ export default memo(shapeComponent(class ApiMakerSuperAdminShowPage extends Base
112
115
  modelArgs[inflection.camelize(modelClass.modelClassData().name, true)] = model
113
116
 
114
117
  return (
115
- <div className="super-admin--show-page">
118
+ <View dataSet={{component: "super-admin--show-page"}}>
116
119
  {model &&
117
120
  <ShowNav model={model} modelClass={modelClass} />
118
121
  }
@@ -123,7 +126,7 @@ export default memo(shapeComponent(class ApiMakerSuperAdminShowPage extends Base
123
126
  <BelongsToAttributeRow key={reflection.name()} model={model} modelClass={modelClass} reflection={reflection} />
124
127
  )}
125
128
  {model && extraContent && extraContent(modelArgs)}
126
- </div>
129
+ </View>
127
130
  )
128
131
  }
129
132
  }))
@@ -7,10 +7,12 @@ import ModelClassTable from "./model-class-table"
7
7
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
8
8
  import ShowNav from "./show-nav"
9
9
  import useQueryParams from "on-location-changed/src/use-query-params"
10
+ import {View} from "react-native"
10
11
 
11
12
  export default memo(shapeComponent(class ApiMakerSuperAdminShowReflectionPage extends BaseComponent {
12
13
  static propTypes = propTypesExact({
13
- modelClass: PropTypes.func.isRequired
14
+ modelClass: PropTypes.func.isRequired,
15
+ modelId: PropTypes.string.isRequired
14
16
  })
15
17
 
16
18
  render() {
@@ -27,7 +29,7 @@ export default memo(shapeComponent(class ApiMakerSuperAdminShowReflectionPage ex
27
29
  if (model) collection = model[reflection.name()]()
28
30
 
29
31
  return (
30
- <div className="super-admin--show-page">
32
+ <View dataSet={{component: "super-admin--show-page"}}>
31
33
  {model &&
32
34
  <ShowNav model={model} modelClass={modelClass} />
33
35
  }
@@ -38,7 +40,7 @@ export default memo(shapeComponent(class ApiMakerSuperAdminShowReflectionPage ex
38
40
  modelClass={reflectionModelClass}
39
41
  />
40
42
  }
41
- </div>
43
+ </View>
42
44
  )
43
45
  }
44
46
  }))
@@ -21,7 +21,7 @@ import Settings from "./settings"
21
21
  import {shapeComponent} from "set-state-compare/src/shape-component"
22
22
  import TableSettings from "./table-settings"
23
23
  import uniqunize from "uniqunize"
24
- import useBreakpoint from "./use-breakpoint"
24
+ import useBreakpoint from "../use-breakpoint"
25
25
  import useCollection from "../use-collection"
26
26
  import useQueryParams from "on-location-changed/src/use-query-params.js"
27
27
 
@@ -175,7 +175,9 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
175
175
  updateSettingsFullCacheKey = () => this.setState({tableSettingFullCacheKey: this.state.tableSetting.fullCacheKey()})
176
176
 
177
177
  columnsAsArray = () => {
178
- if (typeof this.props.columns == "function") return this.props.columns()
178
+ if (typeof this.props.columns == "function") {
179
+ return this.props.columns()
180
+ }
179
181
 
180
182
  return this.props.columns
181
183
  }
@@ -1,9 +0,0 @@
1
- import useBreakpoint from "./use-breakpoint"
2
-
3
- export default (WrappedComponent) => (props) => {
4
- const {breakpoint} = useBreakpoint()
5
-
6
- return (
7
- <WrappedComponent breakPoint={breakpoint} {...props} />
8
- )
9
- }