@kaspernj/api-maker 1.0.325 → 1.0.327

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
@@ -16,7 +16,7 @@
16
16
  ]
17
17
  },
18
18
  "name": "@kaspernj/api-maker",
19
- "version": "1.0.325",
19
+ "version": "1.0.327",
20
20
  "type": "module",
21
21
  "description": "",
22
22
  "main": "index.js",
@@ -49,7 +49,7 @@
49
49
  "js-money": ">= 0.6.3",
50
50
  "numberable": ">= 1.0.0",
51
51
  "object-to-formdata": ">= 4.1.0",
52
- "on-location-changed": ">= 1.0.8",
52
+ "on-location-changed": ">= 1.0.9",
53
53
  "qs": ">= 6.9.3",
54
54
  "replaceall": ">= 0.1.6",
55
55
  "set-state-compare": ">= 1.0.28",
@@ -1,11 +1,14 @@
1
+ import Collection from "./collection.mjs"
1
2
  import {digg} from "diggerize"
2
3
  import {memo, useEffect} from "react"
4
+ import PropTypes from "prop-types"
5
+ import PropTypesExact from "prop-types-exact"
3
6
  import useCollection from "./use-collection"
4
7
  import useShape from "set-state-compare/src/use-shape.js"
5
8
 
6
- const CollectionLoader = (props) => {
7
- const s = useShape(props)
8
- const useCollectionResult = useCollection(props)
9
+ const CollectionLoader = ({component, ...restProps}) => {
10
+ const s = useShape(restProps)
11
+ const useCollectionResult = useCollection(restProps)
9
12
  const cachePartsKeys = [
10
13
  "modelIdsCacheString",
11
14
  "overallCount",
@@ -25,10 +28,10 @@ const CollectionLoader = (props) => {
25
28
  cacheParts.push(digg(useCollectionResult, cachePartsKey))
26
29
  }
27
30
 
28
- s.updateMeta({useCollectionResult})
31
+ s.updateMeta({component, useCollectionResult})
29
32
 
30
33
  useEffect(() => {
31
- const componentShape = digg(s.p.component, "shape")
34
+ const componentShape = digg(s.m.component, "shape")
32
35
 
33
36
  componentShape.set(s.m.useCollectionResult)
34
37
  }, cacheParts)
@@ -36,4 +39,23 @@ const CollectionLoader = (props) => {
36
39
  return null
37
40
  }
38
41
 
42
+ CollectionLoader.propTypes = PropTypesExact({
43
+ abilities: PropTypes.object,
44
+ collection: PropTypes.instanceOf(Collection),
45
+ component: PropTypes.object.isRequired,
46
+ defaultParams: PropTypes.object,
47
+ groupBy: PropTypes.array,
48
+ modelClass: PropTypes.func.isRequired,
49
+ noRecordsAvailableContent: PropTypes.func,
50
+ noRecordsFoundContent: PropTypes.func,
51
+ onModelsLoaded: PropTypes.func,
52
+ pagination: PropTypes.bool.isRequired,
53
+ preloads: PropTypes.array.isRequired,
54
+ queryMethod: PropTypes.func,
55
+ queryName: PropTypes.string,
56
+ ransack: PropTypes.object,
57
+ select: PropTypes.object,
58
+ selectColumns: PropTypes.object
59
+ })
60
+
39
61
  export default memo(CollectionLoader)
@@ -1,65 +1,11 @@
1
- import debounce from "debounce"
2
- import ModelEvents from "./model-events.mjs"
3
- import PropTypes from "prop-types"
4
- import propTypesExact from "prop-types-exact"
5
- import React from "react"
1
+ import useCreatedEvent from "./use-created-event.mjs"
6
2
 
7
- export default class ApiMakerEventCreated extends React.PureComponent {
8
- static defaultProps = {
9
- active: true
10
- }
3
+ const ApiMakerEventCreated = (props) => {
4
+ const {modelClass, onCreated, ...restProps} = props
11
5
 
12
- static propTypes = propTypesExact({
13
- active: PropTypes.bool.isRequired,
14
- debounce: PropTypes.oneOfType([
15
- PropTypes.bool,
16
- PropTypes.number
17
- ]),
18
- modelClass: PropTypes.func.isRequired,
19
- onCreated: PropTypes.func.isRequired
20
- })
6
+ useCreatedEvent(modelClass, onCreated, restProps)
21
7
 
22
- componentDidMount () {
23
- this.connect()
24
- }
25
-
26
- componentWillUnmount () {
27
- if (this.connectCreated) {
28
- this.connectCreated.unsubscribe()
29
- }
30
- }
31
-
32
- connect () {
33
- this.connectCreated = ModelEvents.connectCreated(this.props.modelClass, (...args) => this.onCreated(...args))
34
- }
35
-
36
- debounce () {
37
- if (!this.debounceInstance) {
38
- const {onCreated} = digs(this.props, "onCreated")
39
-
40
- if (typeof this.props.debounce == "number") {
41
- this.debounceInstance = debounce(onCreated, this.props.debounce)
42
- } else {
43
- this.debounceInstance = debounce(onCreated)
44
- }
45
- }
46
-
47
- return this.debounceInstance
48
- }
49
-
50
- onCreated (...args) {
51
- if (!this.props.active) {
52
- return
53
- }
54
-
55
- if (this.props.debounce) {
56
- this.debounce()(...args)
57
- } else {
58
- this.props.onCreated(...args)
59
- }
60
- }
61
-
62
- render () {
63
- return null
64
- }
8
+ return null
65
9
  }
10
+
11
+ export default ApiMakerEventCreated
@@ -1,25 +1,10 @@
1
- import EventEmitter from "events"
2
- import PropTypes from "prop-types"
3
- import React from "react"
1
+ import {memo} from "react"
2
+ import useEventEmitter from "./use-event-emitter.mjs"
4
3
 
5
- export default class ApiMakerEventEmitterListener extends React.PureComponent {
6
- static propTypes = {
7
- event: PropTypes.string.isRequired,
8
- events: PropTypes.instanceOf(EventEmitter).isRequired,
9
- onCalled: PropTypes.func.isRequired
10
- }
4
+ const ApiMakerEventEmitterListener = ({events, event, onCalled}) => {
5
+ useEventEmitter(events, event, onCalled)
11
6
 
12
- componentDidMount () {
13
- this.props.events.addListener(this.props.event, this.onCalled)
14
- }
15
-
16
- componentWillUnmount () {
17
- this.props.events.removeListener(this.props.event, this.onCalled)
18
- }
19
-
20
- onCalled = (...args) => {
21
- this.props.onCalled.apply(null, ...args)
22
- }
23
-
24
- render = () => null
7
+ return null
25
8
  }
9
+
10
+ export default memo(ApiMakerEventEmitterListener)
@@ -1,72 +1,23 @@
1
- import debounce from "debounce"
2
- import ModelEvents from "./model-events.mjs"
3
1
  import PropTypes from "prop-types"
4
2
  import propTypesExact from "prop-types-exact"
5
- import React from "react"
3
+ import {memo} from "react"
4
+ import useUpdatedEvent from "./use-updated-event.mjs"
6
5
 
7
- export default class ApiMakerEventUpdated extends React.PureComponent {
8
- static defaultProps = {
9
- active: true
10
- }
6
+ const ApiMakerEventUpdated = ({model, onUpdated, ...restProps}) => {
7
+ useUpdatedEvent(model, onUpdated, restProps)
11
8
 
12
- static propTypes = propTypesExact({
13
- active: PropTypes.bool.isRequired,
14
- debounce: PropTypes.oneOfType([
15
- PropTypes.bool,
16
- PropTypes.number
17
- ]),
18
- model: PropTypes.object.isRequired,
19
- onConnected: PropTypes.func,
20
- onUpdated: PropTypes.func.isRequired
21
- })
22
-
23
- componentDidMount () {
24
- this.connect()
25
- }
26
-
27
- componentWillUnmount () {
28
- if (this.connectUpdated) {
29
- this.connectUpdated.unsubscribe()
30
- }
31
-
32
- if (this.onConnectedListener) {
33
- this.connectUpdated.events.removeListener("connected", this.props.onConnected)
34
- }
35
- }
36
-
37
- connect () {
38
- const {model, onConnected} = this.props
39
-
40
- this.connectUpdated = ModelEvents.connectUpdated(model, this.onUpdated)
41
-
42
- if (onConnected) {
43
- this.onConnectedListener = this.connectUpdated.events.addListener("connected", this.props.onConnected)
44
- }
45
- }
46
-
47
- debounce () {
48
- if (!this.debounceInstance) {
49
- if (typeof this.props.debounce == "number") {
50
- this.debounceInstance = debounce(this.props.onUpdated, this.props.debounce)
51
- } else {
52
- this.debounceInstance = debounce(this.props.onUpdated)
53
- }
54
- }
55
-
56
- return this.debounceInstance
57
- }
58
-
59
- onUpdated = (...args) => {
60
- if (!this.props.active) {
61
- return
62
- }
63
-
64
- if (this.props.debounce) {
65
- this.debounce()(...args)
66
- } else {
67
- this.props.onUpdated(...args)
68
- }
69
- }
70
-
71
- render = () => null
9
+ return null
72
10
  }
11
+
12
+ ApiMakerEventUpdated.propTypes = propTypesExact({
13
+ active: PropTypes.bool,
14
+ debounce: PropTypes.oneOfType([
15
+ PropTypes.bool,
16
+ PropTypes.number
17
+ ]),
18
+ model: PropTypes.object.isRequired,
19
+ onConnected: PropTypes.func,
20
+ onUpdated: PropTypes.func.isRequired
21
+ })
22
+
23
+ export default memo(ApiMakerEventUpdated)
@@ -1,10 +1,7 @@
1
- import Collection from "./collection.mjs"
2
1
  import debounce from "debounce"
3
2
  import {digg} from "diggerize"
4
3
  import * as inflection from "inflection"
5
4
  import ModelEvents from "./model-events.mjs"
6
- import PropTypes from "prop-types"
7
- import PropTypesExact from "prop-types-exact"
8
5
  import {useCallback, useEffect} from "react"
9
6
  import useShape from "set-state-compare/src/use-shape.js"
10
7
  import useQueryParams from "on-location-changed/src/use-query-params.js"
@@ -15,6 +12,7 @@ const useCollection = (
15
12
  collection,
16
13
  defaultParams,
17
14
  groupBy = ["id"],
15
+ limit,
18
16
  modelClass,
19
17
  noRecordsAvailableContent = undefined,
20
18
  noRecordsFoundContent = undefined,
@@ -23,16 +21,23 @@ const useCollection = (
23
21
  preloads = [],
24
22
  queryMethod,
25
23
  queryName,
24
+ ransack,
26
25
  select = {},
27
- selectColumns
26
+ selectColumns,
27
+ ...restProps
28
28
  },
29
29
  cacheKeys = []
30
30
  ) => {
31
+ if (Object.keys(restProps).length > 0) {
32
+ throw new Error(`Unknown props given to useCollection: ${Object.keys(restProps).join(", ")}`)
33
+ }
34
+
31
35
  const s = useShape({
32
36
  abilities,
33
37
  collection,
34
38
  defaultParams,
35
39
  groupBy,
40
+ limit,
36
41
  modelClass,
37
42
  noRecordsAvailableContent,
38
43
  noRecordsFoundContent,
@@ -40,12 +45,27 @@ const useCollection = (
40
45
  pagination,
41
46
  preloads,
42
47
  queryMethod,
48
+ ransack,
43
49
  select,
44
50
  selectColumns
45
51
  })
46
52
 
53
+ s.meta.queryParams = useQueryParams()
54
+
47
55
  if (!queryName) queryName = digg(modelClass.modelClassData(), "collectionKey")
48
56
 
57
+ const hasQParams = useCallback(() => {
58
+ if (s.s.queryQName in s.m.queryParams) return true
59
+
60
+ return false
61
+ }, [])
62
+
63
+ const qParams = useCallback(() => {
64
+ if (hasQParams()) return JSON.parse(digg(s.m.queryParams, s.s.queryQName))
65
+
66
+ return {}
67
+ }, [])
68
+
49
69
  s.useStates({
50
70
  models: undefined,
51
71
  overallCount: undefined,
@@ -55,14 +75,14 @@ const useCollection = (
55
75
  queryQName: `${queryName}_q`,
56
76
  querySName: `${queryName}_s`,
57
77
  queryPageName: `${queryName}_page`,
58
- qParams: undefined,
59
78
  result: undefined,
60
79
  searchParams: undefined,
61
80
  showNoRecordsAvailableContent: false,
62
81
  showNoRecordsFoundContent: false
63
82
  })
64
-
65
- const queryParams = useQueryParams()
83
+ s.useStates({
84
+ qParams: qParams()
85
+ })
66
86
 
67
87
  let modelIdsCacheString
68
88
 
@@ -74,8 +94,6 @@ const useCollection = (
74
94
  modelIdsCacheString = s.s.models.map((model) => model.cacheKey())?.join("---")
75
95
  }
76
96
 
77
- s.updateMeta({queryParams})
78
-
79
97
  const loadOverallCount = useCallback(async () => {
80
98
  const baseQuery = s.p.collection || s.p.modelClass.all()
81
99
  const overallCount = await baseQuery.count()
@@ -87,18 +105,6 @@ const useCollection = (
87
105
  })
88
106
  }, [])
89
107
 
90
- const hasQParams = useCallback(() => {
91
- if (s.s.queryQName in s.m.queryParams) return true
92
-
93
- return false
94
- }, [])
95
-
96
- const qParams = useCallback(() => {
97
- if (hasQParams()) return JSON.parse(digg(s.m.queryParams, s.s.queryQName))
98
-
99
- return {}
100
- }, [])
101
-
102
108
  const loadQParams = useCallback(() => {
103
109
  const qParamsToSet = hasQParams() ? qParams() : Object.assign({}, s.p.defaultParams)
104
110
  const searchParams = []
@@ -137,6 +143,7 @@ const useCollection = (
137
143
 
138
144
  query = query
139
145
  .ransack(s.s.qParams)
146
+ .ransack(s.props.ransack)
140
147
  .search(s.s.searchParams)
141
148
  .searchKey(s.s.queryQName)
142
149
  .pageKey(s.s.queryPageName)
@@ -145,6 +152,7 @@ const useCollection = (
145
152
  .select(s.p.select)
146
153
 
147
154
  if (s.p.abilities) query = query.abilities(s.p.abilities)
155
+ if (s.p.limit !== undefined) query = query.limit(s.p.limit)
148
156
  if (s.p.selectColumns) query = query.selectColumns(s.p.selectColumns)
149
157
 
150
158
  let result
@@ -235,7 +243,13 @@ const useCollection = (
235
243
  loadQParams()
236
244
  loadModels()
237
245
  },
238
- [queryParams[s.s.queryQName], queryParams[s.s.queryPageName], queryParams[s.s.queryPerKey], queryParams[s.s.querySName], collection].concat(cacheKeys)
246
+ [
247
+ s.m.queryParams[s.s.queryQName],
248
+ s.m.queryParams[s.s.queryPageName],
249
+ s.m.queryParams[s.s.queryPerKey],
250
+ s.m.queryParams[s.s.querySName],
251
+ collection
252
+ ].concat(cacheKeys)
239
253
  )
240
254
 
241
255
  useEffect(() => {
@@ -276,21 +290,4 @@ const useCollection = (
276
290
  return result
277
291
  }
278
292
 
279
- useCollection.propTypes = PropTypesExact({
280
- abilities: PropTypes.object,
281
- collection: PropTypes.instanceOf(Collection),
282
- defaultParams: PropTypes.object,
283
- groupBy: PropTypes.array,
284
- modelClass: PropTypes.func.isRequired,
285
- noRecordsAvailableContent: PropTypes.func,
286
- noRecordsFoundContent: PropTypes.func,
287
- onModelsLoaded: PropTypes.func,
288
- pagination: PropTypes.bool.isRequired,
289
- preloads: PropTypes.array.isRequired,
290
- queryMethod: PropTypes.func,
291
- queryName: PropTypes.string,
292
- select: PropTypes.object,
293
- selectColumns: PropTypes.object
294
- })
295
-
296
293
  export default useCollection
@@ -0,0 +1,55 @@
1
+ import debounceFunction from "debounce"
2
+ import ModelEvents from "./model-events.mjs"
3
+ import PropTypes from "prop-types"
4
+ import propTypesExact from "prop-types-exact"
5
+ import {useCallback, useEffect} from "react"
6
+ import useShape from "set-state-compare/src/use-shape.js"
7
+
8
+ const ApiMakerUseCreatedEvent = (modelClass, onCreated, args = {}) => {
9
+ const {active = true, debounce} = args
10
+ const s = useShape({active, debounce, modelClass, onCreated})
11
+
12
+ const eventDebounce = useCallback(() => {
13
+ if (!s.meta.debounceInstance) {
14
+ if (typeof this.props.debounce == "number") {
15
+ s.meta.debounceInstance = debounceFunction(s.p.onCreated, s.p.debounce)
16
+ } else {
17
+ s.meta.debounceInstance = debounceFunction(s.p.onCreated)
18
+ }
19
+ }
20
+
21
+ return s.meta.debounceInstance
22
+ }, [])
23
+
24
+ const onCreatedCallback = useCallback((...args) => {
25
+ if (!s.p.active) {
26
+ return
27
+ }
28
+
29
+ if (s.p.debounce) {
30
+ eventDebounce()(...args)
31
+ } else {
32
+ s.p.onCreated(...args)
33
+ }
34
+ }, [])
35
+
36
+ useEffect(() => {
37
+ const connectCreated = ModelEvents.connectCreated(s.p.modelClass, (...args) => onCreatedCallback(...args))
38
+
39
+ return () => {
40
+ connectCreated.unsubscribe()
41
+ }
42
+ }, [])
43
+ }
44
+
45
+ ApiMakerUseCreatedEvent.propTypes = propTypesExact({
46
+ active: PropTypes.bool.isRequired,
47
+ debounce: PropTypes.oneOfType([
48
+ PropTypes.bool,
49
+ PropTypes.number
50
+ ]),
51
+ modelClass: PropTypes.func.isRequired,
52
+ onCreated: PropTypes.func.isRequired
53
+ })
54
+
55
+ export default ApiMakerUseCreatedEvent
@@ -0,0 +1,25 @@
1
+ import EventEmitter from "events"
2
+ import PropTypes from "prop-types"
3
+ import {useCallback, useEffect} from "react"
4
+
5
+ const ApiMakerUseEventEmitter = (events, event, onCalled) => {
6
+ const onCalledCallback = useCallback((...args) => {
7
+ onCalled.apply(null, ...args)
8
+ }, [events, event, onCalled])
9
+
10
+ useEffect(() => {
11
+ events.addListener(event, onCalledCallback)
12
+
13
+ return () => {
14
+ events.removeListener(event, onCalledCallback)
15
+ }
16
+ }, [events, event, onCalled])
17
+ }
18
+
19
+ ApiMakerUseEventEmitter.propTypes = {
20
+ event: PropTypes.string.isRequired,
21
+ events: PropTypes.instanceOf(EventEmitter).isRequired,
22
+ onCalled: PropTypes.func.isRequired
23
+ }
24
+
25
+ export default ApiMakerUseEventEmitter
@@ -0,0 +1,58 @@
1
+ import {useCallback, useEffect, useMemo} from "react"
2
+ import debounceFunction from "debounce"
3
+ import ModelEvents from "./model-events.mjs"
4
+ import useShape from "set-state-compare/src/use-shape.js"
5
+
6
+ const ApiMakerUseUpdatedEvent = (model, onUpdated, {active = true, debounce, onConnected, ...restProps}) => {
7
+ if (Object.keys(restProps).length > 0) {
8
+ throw new Error(`Unknown props given to useUpdatedEvent: ${Object.keys(restProps).join(", ")}`)
9
+ }
10
+
11
+ const s = useShape({active, debounce, model, onUpdated})
12
+
13
+ const debounceCallback = useMemo(() => {
14
+ if (typeof debounce == "number") {
15
+ return debounceFunction(s.p.onUpdated, debounce)
16
+ } else {
17
+ return debounceFunction(s.p.onUpdated)
18
+ }
19
+ }, [debounce])
20
+
21
+ s.updateMeta({debounceCallback})
22
+
23
+ const onUpdatedCallback = useCallback((...args) => {
24
+ if (!s.p.active) {
25
+ return
26
+ }
27
+
28
+ if (s.p.debounce) {
29
+ s.m.debounceCallback(...args)
30
+ } else {
31
+ s.p.onUpdated(...args)
32
+ }
33
+ }, [])
34
+
35
+ useEffect(() => {
36
+ let connectUpdated, onConnectedListener
37
+
38
+ if (model) {
39
+ connectUpdated = ModelEvents.connectUpdated(model, onUpdatedCallback)
40
+
41
+ if (onConnected) {
42
+ onConnectedListener = connectUpdated.events.addListener("connected", onConnected)
43
+ }
44
+ }
45
+
46
+ return () => {
47
+ if (onConnectedListener) {
48
+ connectUpdated.events.removeListener("connected", onConnected)
49
+ }
50
+
51
+ if (connectUpdated) {
52
+ connectUpdated.unsubscribe()
53
+ }
54
+ }
55
+ }, [model?.id()])
56
+ }
57
+
58
+ export default ApiMakerUseUpdatedEvent