form create added
This commit is contained in:
parent
44c458cd4c
commit
6720c69e6f
|
|
@ -12,14 +12,16 @@
|
||||||
"@radix-ui/react-avatar": "^1.1.1",
|
"@radix-ui/react-avatar": "^1.1.1",
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-popover": "^1.1.2",
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.1",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.1",
|
||||||
"@radix-ui/react-switch": "^1.1.1",
|
"@radix-ui/react-switch": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
|
"chrono-node": "^2.7.7",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
|
"date-fns": "^3.6.0",
|
||||||
"flatpickr": "^4.6.13",
|
"flatpickr": "^4.6.13",
|
||||||
"jsvectormap": "^1.6.0",
|
"jsvectormap": "^1.6.0",
|
||||||
"lucide-react": "^0.462.0",
|
"lucide-react": "^0.462.0",
|
||||||
|
|
@ -28,6 +30,7 @@
|
||||||
"next-themes": "^0.4.3",
|
"next-themes": "^0.4.3",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-apexcharts": "^1.6.0",
|
"react-apexcharts": "^1.6.0",
|
||||||
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.2",
|
"react-hook-form": "^7.53.2",
|
||||||
"react-phone-number-input": "^3.4.9",
|
"react-phone-number-input": "^3.4.9",
|
||||||
|
|
@ -685,11 +688,33 @@
|
||||||
"integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="
|
"integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-arrow": {
|
"node_modules/@radix-ui/react-arrow": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz",
|
||||||
"integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==",
|
"integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-primitive": "2.0.0"
|
"@radix-ui/react-primitive": "2.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
|
|
@ -770,6 +795,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-compose-refs": {
|
"node_modules/@radix-ui/react-compose-refs": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
|
||||||
|
|
@ -833,6 +875,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-direction": {
|
"node_modules/@radix-ui/react-direction": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
||||||
|
|
@ -951,25 +1010,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-popover": {
|
"node_modules/@radix-ui/react-popover": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.4.tgz",
|
||||||
"integrity": "sha512-u2HRUyWW+lOiA2g0Le0tMmT55FGOEWHwPFt1EPfbLly7uXQExFo5duNKqG2DzmFXIdqOeNd+TpE8baHWJCyP9w==",
|
"integrity": "sha512-aUACAkXx8LaFymDma+HQVji7WhvEhpFJ7+qPz17Nf4lLZqtreGOFRiNQWQmhzp7kEWg9cOyyQJpdIMUMPc/CPw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/primitive": "1.1.0",
|
"@radix-ui/primitive": "1.1.1",
|
||||||
"@radix-ui/react-compose-refs": "1.1.0",
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
"@radix-ui/react-context": "1.1.1",
|
"@radix-ui/react-context": "1.1.1",
|
||||||
"@radix-ui/react-dismissable-layer": "1.1.1",
|
"@radix-ui/react-dismissable-layer": "1.1.3",
|
||||||
"@radix-ui/react-focus-guards": "1.1.1",
|
"@radix-ui/react-focus-guards": "1.1.1",
|
||||||
"@radix-ui/react-focus-scope": "1.1.0",
|
"@radix-ui/react-focus-scope": "1.1.1",
|
||||||
"@radix-ui/react-id": "1.1.0",
|
"@radix-ui/react-id": "1.1.0",
|
||||||
"@radix-ui/react-popper": "1.2.0",
|
"@radix-ui/react-popper": "1.2.1",
|
||||||
"@radix-ui/react-portal": "1.1.2",
|
"@radix-ui/react-portal": "1.1.3",
|
||||||
"@radix-ui/react-presence": "1.1.1",
|
"@radix-ui/react-presence": "1.1.2",
|
||||||
"@radix-ui/react-primitive": "2.0.0",
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
"@radix-ui/react-slot": "1.1.0",
|
"@radix-ui/react-slot": "1.1.1",
|
||||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
"aria-hidden": "^1.1.1",
|
"aria-hidden": "^1.1.1",
|
||||||
"react-remove-scroll": "2.6.0"
|
"react-remove-scroll": "^2.6.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
|
|
@ -986,16 +1045,177 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
|
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover/node_modules/react-remove-scroll": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==",
|
||||||
|
"dependencies": {
|
||||||
|
"react-remove-scroll-bar": "^2.3.7",
|
||||||
|
"react-style-singleton": "^2.2.1",
|
||||||
|
"tslib": "^2.1.0",
|
||||||
|
"use-callback-ref": "^1.3.3",
|
||||||
|
"use-sidecar": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-popper": {
|
"node_modules/@radix-ui/react-popper": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
|
||||||
"integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==",
|
"integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/react-dom": "^2.0.0",
|
"@floating-ui/react-dom": "^2.0.0",
|
||||||
"@radix-ui/react-arrow": "1.1.0",
|
"@radix-ui/react-arrow": "1.1.1",
|
||||||
"@radix-ui/react-compose-refs": "1.1.0",
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
"@radix-ui/react-context": "1.1.0",
|
"@radix-ui/react-context": "1.1.1",
|
||||||
"@radix-ui/react-primitive": "2.0.0",
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||||
"@radix-ui/react-use-rect": "1.1.0",
|
"@radix-ui/react-use-rect": "1.1.0",
|
||||||
|
|
@ -1017,10 +1237,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": {
|
"node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-compose-refs": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
"integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
|
@ -1031,6 +1251,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-portal": {
|
"node_modules/@radix-ui/react-portal": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz",
|
||||||
|
|
@ -1099,18 +1341,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-scroll-area": {
|
"node_modules/@radix-ui/react-scroll-area": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.2.tgz",
|
||||||
"integrity": "sha512-FnM1fHfCtEZ1JkyfH/1oMiTcFBQvHKl4vD9WnpwkLgtF+UmnXMCad6ECPTaAjcDjam+ndOEJWgHyKDGNteWSHw==",
|
"integrity": "sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/number": "1.1.0",
|
"@radix-ui/number": "1.1.0",
|
||||||
"@radix-ui/primitive": "1.1.0",
|
"@radix-ui/primitive": "1.1.1",
|
||||||
"@radix-ui/react-compose-refs": "1.1.0",
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
"@radix-ui/react-context": "1.1.1",
|
"@radix-ui/react-context": "1.1.1",
|
||||||
"@radix-ui/react-direction": "1.1.0",
|
"@radix-ui/react-direction": "1.1.0",
|
||||||
"@radix-ui/react-presence": "1.1.1",
|
"@radix-ui/react-presence": "1.1.2",
|
||||||
"@radix-ui/react-primitive": "2.0.0",
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
},
|
},
|
||||||
|
|
@ -1129,13 +1388,91 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-slot": {
|
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||||
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
|
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
|
||||||
"dependencies": {
|
},
|
||||||
"@radix-ui/react-compose-refs": "1.1.0"
|
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
},
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
|
@ -1629,6 +1966,17 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chrono-node": {
|
||||||
|
"version": "2.7.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-2.7.7.tgz",
|
||||||
|
"integrity": "sha512-p3S7gotuTPu5oqhRL2p1fLwQXGgdQaRTtWR3e8Di9P1Pa9mzkK5DWR5AWBieMUh2ZdOnPgrK+zCrbbtyuA+D/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"dayjs": "^1.10.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/class-variance-authority": {
|
"node_modules/class-variance-authority": {
|
||||||
"version": "0.7.1",
|
"version": "0.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
||||||
|
|
@ -1755,6 +2103,20 @@
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||||
|
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
|
||||||
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||||
|
|
@ -1944,14 +2306,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/invariant": {
|
|
||||||
"version": "2.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
|
||||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||||
|
|
@ -2548,6 +2902,19 @@
|
||||||
"react": ">=0.13"
|
"react": ">=0.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-day-picker": {
|
||||||
|
"version": "8.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz",
|
||||||
|
"integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==",
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/gpbl"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"date-fns": "^2.28.0 || ^3.0.0",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
|
|
@ -2621,19 +2988,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-remove-scroll-bar": {
|
"node_modules/react-remove-scroll-bar": {
|
||||||
"version": "2.3.6",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||||
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
|
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-style-singleton": "^2.2.1",
|
"react-style-singleton": "^2.2.2",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "*",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
|
@ -2642,20 +3009,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-style-singleton": {
|
"node_modules/react-style-singleton": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||||
"integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
|
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"get-nonce": "^1.0.0",
|
"get-nonce": "^1.0.0",
|
||||||
"invariant": "^2.2.4",
|
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "*",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
|
@ -3107,9 +3473,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/use-callback-ref": {
|
"node_modules/use-callback-ref": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||||
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
|
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
|
|
@ -3117,8 +3483,8 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "*",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,16 @@
|
||||||
"@radix-ui/react-avatar": "^1.1.1",
|
"@radix-ui/react-avatar": "^1.1.1",
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-popover": "^1.1.2",
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.1",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.1",
|
||||||
"@radix-ui/react-switch": "^1.1.1",
|
"@radix-ui/react-switch": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
|
"chrono-node": "^2.7.7",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
|
"date-fns": "^3.6.0",
|
||||||
"flatpickr": "^4.6.13",
|
"flatpickr": "^4.6.13",
|
||||||
"jsvectormap": "^1.6.0",
|
"jsvectormap": "^1.6.0",
|
||||||
"lucide-react": "^0.462.0",
|
"lucide-react": "^0.462.0",
|
||||||
|
|
@ -29,6 +31,7 @@
|
||||||
"next-themes": "^0.4.3",
|
"next-themes": "^0.4.3",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-apexcharts": "^1.6.0",
|
"react-apexcharts": "^1.6.0",
|
||||||
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.2",
|
"react-hook-form": "^7.53.2",
|
||||||
"react-phone-number-input": "^3.4.9",
|
"react-phone-number-input": "^3.4.9",
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,6 @@ const Build: React.FC = () => {
|
||||||
...prev,
|
...prev,
|
||||||
[key]: component.component,
|
[key]: component.component,
|
||||||
}));
|
}));
|
||||||
} else {
|
|
||||||
setEndpointNeedsList((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[key]: component.notAllowed,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import * as z from "zod";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { SmartDatetimeInput } from "@/components/ui/smart-datetime-input";
|
||||||
|
|
||||||
interface FormPageInterface {
|
interface FormPageInterface {
|
||||||
validatedData: any;
|
validatedData: any;
|
||||||
|
|
@ -36,20 +37,16 @@ const FormPage: React.FC<FormPageInterface> = ({
|
||||||
...validatedData,
|
...validatedData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
function submitUpdate(formData: z.infer<typeof validSchemaZod>) {
|
||||||
function submitUpdate(formData: FormData) {
|
let newDataForm: any = {};
|
||||||
let newFormData: any = {};
|
Object.entries(formData).map(([key, value]) => {
|
||||||
Object.entries(Object.fromEntries(formData)).forEach(([key, value]) => {
|
if (typeof value === "number" && value !== 0) {
|
||||||
if (apiValidation[key].fieldType === "integer") {
|
newDataForm[key] = value;
|
||||||
const newNumber = typeof value === "string" ? 0 : Number(value);
|
} else if (typeof value === "string" && value !== "") {
|
||||||
newFormData[key] = newNumber;
|
newDataForm[key] = value;
|
||||||
} else {
|
|
||||||
newFormData[key] = value;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const validated = validSchemaZod.safeParse(newFormData);
|
console.log(newDataForm);
|
||||||
console.log("validated", validated);
|
|
||||||
console.log("validated", validated.error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -58,8 +55,7 @@ const FormPage: React.FC<FormPageInterface> = ({
|
||||||
<div>
|
<div>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
action={submitUpdate}
|
onSubmit={form.handleSubmit(submitUpdate)}
|
||||||
// onSubmit={form.handleSubmit(submitUpdate)}
|
|
||||||
className="space-y-5 max-w-3xl mx-auto py-10"
|
className="space-y-5 max-w-3xl mx-auto py-10"
|
||||||
>
|
>
|
||||||
<div className=" absolute w-[80px] right-20 bg-emerald-700">
|
<div className=" absolute w-[80px] right-20 bg-emerald-700">
|
||||||
|
|
@ -89,88 +85,96 @@ const FormPage: React.FC<FormPageInterface> = ({
|
||||||
if (apiValidation[key]?.fieldType === "string") {
|
if (apiValidation[key]?.fieldType === "string") {
|
||||||
return (
|
return (
|
||||||
<div className="mb-4" key={`${key}-header`}>
|
<div className="mb-4" key={`${key}-header`}>
|
||||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
|
||||||
{apiHeaders[key]}
|
|
||||||
</label>
|
|
||||||
<div className="relative" key={key}>
|
<div className="relative" key={key}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className="absolute right-4 top-1/2 lucide lucide-pencil"
|
||||||
|
>
|
||||||
|
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
||||||
|
<path d="m15 5 4 4" />
|
||||||
|
</svg>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name={key as keyof z.infer<typeof zodValidation>}
|
name={String(key)}
|
||||||
render={({ field }) => (
|
render={({ field }) => {
|
||||||
<FormItem>
|
return (
|
||||||
<FormControl>
|
<FormItem>
|
||||||
<input
|
<FormLabel>{apiHeaders[key]}</FormLabel>
|
||||||
type="text"
|
<FormControl>
|
||||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
<SmartDatetimeInput
|
||||||
{...field}
|
value={field.value}
|
||||||
value={field.value}
|
onValueChange={field.onChange}
|
||||||
/>
|
placeholder="e.g. Tomorrow morning 9am"
|
||||||
</FormControl>
|
/>
|
||||||
<FormMessage />
|
</FormControl>
|
||||||
</FormItem>
|
{String(form.formState.errors[key]?.type) ===
|
||||||
)}
|
"invalid_type" ? (
|
||||||
|
<span id={key} className="text-red-700">
|
||||||
|
"Lütfen sayısal bir değer giriniz"
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="absolute right-4 top-4">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="lucide lucide-pencil"
|
|
||||||
>
|
|
||||||
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
|
||||||
<path d="m15 5 4 4" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (apiValidation[key]?.fieldType === "integer") {
|
} else if (apiValidation[key]?.fieldType === "integer") {
|
||||||
return (
|
return (
|
||||||
<div className="mb-4" key={`${key}-header`}>
|
<div className="mb-4" key={`${key}-header`}>
|
||||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
|
||||||
{apiHeaders[key]}
|
|
||||||
</label>
|
|
||||||
<div className="relative" key={key}>
|
<div className="relative" key={key}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className="absolute right-4 top-1/2 lucide lucide-pencil"
|
||||||
|
>
|
||||||
|
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
||||||
|
<path d="m15 5 4 4" />
|
||||||
|
</svg>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name={key as keyof z.infer<typeof zodValidation>}
|
name={String(key)}
|
||||||
render={({ field }) => (
|
render={({ field }) => {
|
||||||
<FormItem>
|
return (
|
||||||
<FormControl>
|
<FormItem>
|
||||||
<input
|
<FormLabel>{apiHeaders[key]}</FormLabel>
|
||||||
type="number"
|
<FormControl>
|
||||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
<Input
|
||||||
{...field}
|
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
||||||
value={field.value || ""}
|
{...field}
|
||||||
/>
|
value={field.value || ""}
|
||||||
</FormControl>
|
/>
|
||||||
<FormMessage />
|
</FormControl>
|
||||||
</FormItem>
|
{String(form.formState.errors[key]?.type) ===
|
||||||
)}
|
"invalid_type" ? (
|
||||||
|
<span id={key} className="text-red-700">
|
||||||
|
"Lütfen sayısal bir değer giriniz"
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="absolute right-4 top-4">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="lucide lucide-pencil"
|
|
||||||
>
|
|
||||||
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
|
||||||
<path d="m15 5 4 4" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
"use client";
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
|
||||||
|
import * as z from "zod";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { SmartDatetimeInput } from "@/components/ui/smart-datetime-input";
|
||||||
|
|
||||||
|
interface FormPageValidInterface {
|
||||||
|
zodValidation: any;
|
||||||
|
apiValidation: any;
|
||||||
|
apiHeaders: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormPageValid: React.FC<FormPageValidInterface> = ({
|
||||||
|
zodValidation,
|
||||||
|
apiValidation,
|
||||||
|
apiHeaders,
|
||||||
|
}) => {
|
||||||
|
const validSchemaZod = z.object({ ...zodValidation });
|
||||||
|
|
||||||
|
const form = useForm<z.infer<typeof validSchemaZod>>({
|
||||||
|
resolver: zodResolver(validSchemaZod),
|
||||||
|
});
|
||||||
|
function submitUpdate(formData: z.infer<typeof validSchemaZod>) {
|
||||||
|
let newDataForm: any = {};
|
||||||
|
Object.entries(formData).map(([key, value]) => {
|
||||||
|
if (typeof value === "number" && value !== 0) {
|
||||||
|
newDataForm[key] = value;
|
||||||
|
} else if (typeof value === "string" && value !== "") {
|
||||||
|
newDataForm[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(newDataForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<Form {...form}>
|
||||||
|
<form
|
||||||
|
onSubmit={form.handleSubmit(submitUpdate)}
|
||||||
|
className="space-y-5 max-w-3xl mx-auto py-10"
|
||||||
|
>
|
||||||
|
<div className=" absolute w-[80px] right-20 bg-emerald-700">
|
||||||
|
<span>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className="lucide lucide-check"
|
||||||
|
>
|
||||||
|
<path d="M20 6 9 17l-5-5" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value="Kaydet"
|
||||||
|
className="w-full cursor-pointer rounded-lg border p-4 text-white transition hover:bg-opacity-90"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{Object.keys(zodValidation).map((key: string) => {
|
||||||
|
if (apiValidation[key]?.fieldType === "string") {
|
||||||
|
return (
|
||||||
|
<div className="mb-4" key={`${key}-header`}>
|
||||||
|
<div className="relative" key={key}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className="absolute right-4 top-1/2 lucide lucide-pencil"
|
||||||
|
>
|
||||||
|
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
||||||
|
<path d="m15 5 4 4" />
|
||||||
|
</svg>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={String(key)}
|
||||||
|
render={({ field }) => {
|
||||||
|
return (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{apiHeaders[key]}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<SmartDatetimeInput
|
||||||
|
value={field.value}
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
placeholder="e.g. Tomorrow morning 9am"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
{String(form.formState.errors[key]?.type) ===
|
||||||
|
"invalid_type" ? (
|
||||||
|
<span id={key} className="text-red-700">
|
||||||
|
"Lütfen sayısal bir değer giriniz"
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (apiValidation[key]?.fieldType === "integer") {
|
||||||
|
return (
|
||||||
|
<div className="mb-4" key={`${key}-header`}>
|
||||||
|
<div className="relative" key={key}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className="absolute right-4 top-1/2 lucide lucide-pencil"
|
||||||
|
>
|
||||||
|
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
||||||
|
<path d="m15 5 4 4" />
|
||||||
|
</svg>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={String(key)}
|
||||||
|
render={({ field }) => {
|
||||||
|
return (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{apiHeaders[key]}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
||||||
|
{...field}
|
||||||
|
value={field.value || ""}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
{String(form.formState.errors[key]?.type) ===
|
||||||
|
"invalid_type" ? (
|
||||||
|
<span id={key} className="text-red-700">
|
||||||
|
"Lütfen sayısal bir değer giriniz"
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FormPageValid;
|
||||||
|
|
@ -15,19 +15,22 @@ import { z } from "zod";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { retrieveValidationsByEndpoint } from "../functions/retrieveEndpointAndValidations";
|
import { retrieveValidationsByEndpoint } from "../functions/retrieveEndpointAndValidations";
|
||||||
|
import FormPageValid from "./FormPageValid";
|
||||||
|
|
||||||
interface CreatePageProps {
|
interface CreatePageProps {
|
||||||
pageInfo: any;
|
pageInfo: any;
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
returnToPage: any;
|
returnToPage: any;
|
||||||
|
saveFunction: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreatePage: React.FC<CreatePageProps> = ({
|
const CreatePage: React.FC<CreatePageProps> = ({
|
||||||
pageInfo,
|
pageInfo,
|
||||||
endpoint,
|
endpoint,
|
||||||
returnToPage,
|
returnToPage,
|
||||||
|
saveFunction,
|
||||||
}) => {
|
}) => {
|
||||||
const [zodValidation, setZodValidation] = React.useState(z.object({}));
|
const [zodValidation, setZodValidation] = React.useState(null);
|
||||||
const [apiValidation, setApiValidation] = React.useState<{
|
const [apiValidation, setApiValidation] = React.useState<{
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}>({});
|
}>({});
|
||||||
|
|
@ -37,18 +40,13 @@ const CreatePage: React.FC<CreatePageProps> = ({
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
retrieveValidationsByEndpoint(endpoint).then((validations: any) => {
|
retrieveValidationsByEndpoint(endpoint).then((validations: any) => {
|
||||||
setZodValidation(validations.zodValidation as any);
|
setZodValidation(validations.zodValidation);
|
||||||
setApiHeaders(validations.apiValidation?.headers as Object);
|
setApiValidation(validations.apiValidation?.validated);
|
||||||
setApiValidation(validations.apiValidation?.validated as Object);
|
setApiHeaders(validations.apiValidation?.headers);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof zodValidation>>({
|
|
||||||
resolver: zodResolver(zodValidation),
|
|
||||||
});
|
|
||||||
|
|
||||||
function closeFormPage() {}
|
|
||||||
function saveAction() {}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -77,135 +75,14 @@ const CreatePage: React.FC<CreatePageProps> = ({
|
||||||
</svg>
|
</svg>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="absolute right-0">
|
|
||||||
<EventButton
|
|
||||||
onClick={() => saveAction()}
|
|
||||||
label="Kaydet"
|
|
||||||
bgColor="bg-emerald-700"
|
|
||||||
icon={
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="lucide lucide-check"
|
|
||||||
>
|
|
||||||
<path d="M20 6 9 17l-5-5" />
|
|
||||||
</svg>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{zodValidation && apiValidation && (
|
||||||
<Form {...form}>
|
<FormPageValid
|
||||||
<form
|
zodValidation={zodValidation}
|
||||||
onSubmit={form.handleSubmit()}
|
apiValidation={apiValidation}
|
||||||
className="space-y-5 max-w-3xl mx-auto py-10"
|
apiHeaders={apiHeaders}
|
||||||
>
|
/>
|
||||||
{Object.keys(apiValidation).map((key: string) => {
|
)}
|
||||||
const keyValidation = apiValidation[key] || {
|
|
||||||
fieldType: { type: "string" },
|
|
||||||
required: false,
|
|
||||||
};
|
|
||||||
const fieldType = keyValidation.fieldType?.type || "string";
|
|
||||||
if (fieldType === "string" && apiValidation[key]) {
|
|
||||||
return (
|
|
||||||
<div className="mb-4" key={`${key}-header`}>
|
|
||||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
|
||||||
{apiHeaders[key]}
|
|
||||||
</label>
|
|
||||||
<div className="relative" key={key}>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name={key as keyof z.infer<typeof zodValidation>}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
|
||||||
{...field}
|
|
||||||
value={field.value}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<span className="absolute right-4 top-4">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="lucide lucide-pencil"
|
|
||||||
>
|
|
||||||
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
|
||||||
<path d="m15 5 4 4" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (fieldType === "integer" && apiValidation[key]) {
|
|
||||||
return (
|
|
||||||
<div className="mb-4" key={`${key}-header`}>
|
|
||||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
|
||||||
{apiHeaders[key]}
|
|
||||||
</label>
|
|
||||||
<div className="relative" key={key}>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name={key as keyof z.infer<typeof zodValidation>}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
|
||||||
{...field}
|
|
||||||
value={field.value}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<span className="absolute right-4 top-4">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="lucide lucide-pencil"
|
|
||||||
>
|
|
||||||
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
|
|
||||||
<path d="m15 5 4 4" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</form>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import React from "react";
|
||||||
import EventButton from "./ButtonEvent";
|
import EventButton from "./ButtonEvent";
|
||||||
import FormPage from "./FormPage";
|
import FormPage from "./FormPage";
|
||||||
|
|
||||||
import * as z from "zod";
|
|
||||||
import { retrieveValidationsByEndpointWithData } from "../functions/retrieveEndpointAndValidations";
|
import { retrieveValidationsByEndpointWithData } from "../functions/retrieveEndpointAndValidations";
|
||||||
|
|
||||||
interface UpdatePageButtonProps {
|
interface UpdatePageButtonProps {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import {
|
||||||
retrieveHeadersAndValidationByEndpoint,
|
retrieveHeadersAndValidationByEndpoint,
|
||||||
retrieveHeadersEndpoint,
|
retrieveHeadersEndpoint,
|
||||||
} from "@/(apicalls)/validations/validations";
|
} from "@/(apicalls)/validations/validations";
|
||||||
|
import { ZodDecimal } from "@/components/zodDecimal";
|
||||||
|
|
||||||
async function retrieveValidationsByEndpoint(endpoint: string) {
|
async function retrieveValidationsByEndpoint(endpoint: string) {
|
||||||
let apiValidation: any = {};
|
let apiValidation: any = {};
|
||||||
|
|
@ -97,11 +98,8 @@ async function retrieveValidationsByEndpointWithData(
|
||||||
.refine((val) => val !== "" || val !== null);
|
.refine((val) => val !== "" || val !== null);
|
||||||
} else if (fieldType === "integer") {
|
} else if (fieldType === "integer") {
|
||||||
zodValidation[key] = required
|
zodValidation[key] = required
|
||||||
? z.number().transform((val) => Number(val))
|
? ZodDecimal.create({ coerce: true })
|
||||||
: z
|
: ZodDecimal.create({ coerce: true }).optional();
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.transform((val) => Number(val));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||||
|
import { DayPicker } from "react-day-picker"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { buttonVariants } from "@/components/ui/button"
|
||||||
|
|
||||||
|
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
||||||
|
|
||||||
|
function Calendar({
|
||||||
|
className,
|
||||||
|
classNames,
|
||||||
|
showOutsideDays = true,
|
||||||
|
...props
|
||||||
|
}: CalendarProps) {
|
||||||
|
return (
|
||||||
|
<DayPicker
|
||||||
|
showOutsideDays={showOutsideDays}
|
||||||
|
className={cn("p-3", className)}
|
||||||
|
classNames={{
|
||||||
|
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
||||||
|
month: "space-y-4",
|
||||||
|
caption: "flex justify-center pt-1 relative items-center",
|
||||||
|
caption_label: "text-sm font-medium",
|
||||||
|
nav: "space-x-1 flex items-center",
|
||||||
|
nav_button: cn(
|
||||||
|
buttonVariants({ variant: "outline" }),
|
||||||
|
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
||||||
|
),
|
||||||
|
nav_button_previous: "absolute left-1",
|
||||||
|
nav_button_next: "absolute right-1",
|
||||||
|
table: "w-full border-collapse space-y-1",
|
||||||
|
head_row: "flex",
|
||||||
|
head_cell:
|
||||||
|
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
||||||
|
row: "flex w-full mt-2",
|
||||||
|
cell: cn(
|
||||||
|
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
|
||||||
|
props.mode === "range"
|
||||||
|
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
|
||||||
|
: "[&:has([aria-selected])]:rounded-md"
|
||||||
|
),
|
||||||
|
day: cn(
|
||||||
|
buttonVariants({ variant: "ghost" }),
|
||||||
|
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
|
||||||
|
),
|
||||||
|
day_range_start: "day-range-start",
|
||||||
|
day_range_end: "day-range-end",
|
||||||
|
day_selected:
|
||||||
|
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
||||||
|
day_today: "bg-accent text-accent-foreground",
|
||||||
|
day_outside:
|
||||||
|
"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
|
||||||
|
day_disabled: "text-muted-foreground opacity-50",
|
||||||
|
day_range_middle:
|
||||||
|
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
||||||
|
day_hidden: "invisible",
|
||||||
|
...classNames,
|
||||||
|
}}
|
||||||
|
components={{
|
||||||
|
IconLeft: ({ className, ...props }) => (
|
||||||
|
<ChevronLeft className={cn("h-4 w-4", className)} {...props} />
|
||||||
|
),
|
||||||
|
IconRight: ({ className, ...props }) => (
|
||||||
|
<ChevronRight className={cn("h-4 w-4", className)} {...props} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Calendar.displayName = "Calendar"
|
||||||
|
|
||||||
|
export { Calendar }
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react";
|
import * as React from "react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||||
({ className, type, ...props }, ref) => {
|
({ className, type, ...props }, ref) => {
|
||||||
|
|
@ -8,15 +8,15 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-14 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
Input.displayName = "Input";
|
Input.displayName = "Input"
|
||||||
|
|
||||||
export { Input };
|
export { Input }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,551 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { parseDate } from "chrono-node";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { ActiveModifiers } from "react-day-picker";
|
||||||
|
import { Calendar, CalendarProps } from "@/components/ui/calendar";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Calendar as CalendarIcon, LucideTextCursorInput } from "lucide-react";
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Inspired By: */
|
||||||
|
/* @steventey */
|
||||||
|
/* ------------------https://dub.co/blog/smart-datetime-picker--------------- */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function that parses dates.
|
||||||
|
* Parses a given date string using the `chrono-node` library.
|
||||||
|
*
|
||||||
|
* @param str - A string representation of a date and time.
|
||||||
|
* @returns A `Date` object representing the parsed date and time, or `null` if the string could not be parsed.
|
||||||
|
*/
|
||||||
|
export const parseDateTime = (str: Date | string) => {
|
||||||
|
if (str instanceof Date) return str;
|
||||||
|
return parseDate(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a given timestamp or the current date and time to a string representation in the local time zone.
|
||||||
|
* format: `HH:mm`, adjusted for the local time zone.
|
||||||
|
*
|
||||||
|
* @param timestamp {Date | string}
|
||||||
|
* @returns A string representation of the timestamp
|
||||||
|
*/
|
||||||
|
export const getDateTimeLocal = (timestamp?: Date): string => {
|
||||||
|
const d = timestamp ? new Date(timestamp) : new Date();
|
||||||
|
if (d.toString() === "Invalid Date") return "";
|
||||||
|
return new Date(d.getTime() - d.getTimezoneOffset() * 60000)
|
||||||
|
.toISOString()
|
||||||
|
.split(":")
|
||||||
|
.slice(0, 2)
|
||||||
|
.join(":");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a given date and time object or string into a human-readable string representation.
|
||||||
|
* "MMM D, YYYY h:mm A" (e.g. "Jan 1, 2023 12:00 PM").
|
||||||
|
*
|
||||||
|
* @param datetime - {Date | string}
|
||||||
|
* @returns A string representation of the date and time
|
||||||
|
*/
|
||||||
|
export const formatDateTime = (datetime: Date | string) => {
|
||||||
|
return new Date(datetime).toLocaleTimeString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputBase =
|
||||||
|
"bg-transparent focus:outline-none focus:ring-0 focus-within:outline-none focus-within:ring-0 sm:text-sm disabled:cursor-not-allowed disabled:opacity-50";
|
||||||
|
|
||||||
|
// @source: https://www.perplexity.ai/search/in-javascript-how-RfI7fMtITxKr5c.V9Lv5KA#1
|
||||||
|
// use this pattern to validate the transformed date string for the natural language input
|
||||||
|
const naturalInputValidationPattern =
|
||||||
|
"^[A-Z][a-z]{2}sd{1,2},sd{4},sd{1,2}:d{2}s[AP]M$";
|
||||||
|
|
||||||
|
const DEFAULT_SIZE = 96;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smart time input Docs: {@link: https://shadcn-extension.vercel.app/docs/smart-time-input}
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface SmartDatetimeInputProps {
|
||||||
|
value?: Date;
|
||||||
|
onValueChange: (date: Date) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SmartDatetimeInputContextProps extends SmartDatetimeInputProps {
|
||||||
|
Time: string;
|
||||||
|
onTimeChange: (time: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmartDatetimeInputContext =
|
||||||
|
React.createContext<SmartDatetimeInputContextProps | null>(null);
|
||||||
|
|
||||||
|
const useSmartDateInput = () => {
|
||||||
|
const context = React.useContext(SmartDatetimeInputContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
"useSmartDateInput must be used within SmartDateInputProvider",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SmartDatetimeInput = React.forwardRef<
|
||||||
|
HTMLInputElement,
|
||||||
|
Omit<
|
||||||
|
React.InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
"type" | "ref" | "value" | "defaultValue" | "onBlur"
|
||||||
|
> &
|
||||||
|
SmartDatetimeInputProps
|
||||||
|
>(({ className, value, onValueChange, placeholder, disabled }, ref) => {
|
||||||
|
// ? refactor to be only used with controlled input
|
||||||
|
/* const [dateTime, setDateTime] = React.useState<Date | undefined>(
|
||||||
|
value ?? undefined
|
||||||
|
); */
|
||||||
|
|
||||||
|
const [Time, setTime] = React.useState<string>("");
|
||||||
|
|
||||||
|
const onTimeChange = React.useCallback((time: string) => {
|
||||||
|
setTime(time);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SmartDatetimeInputContext.Provider
|
||||||
|
value={{ value, onValueChange, Time, onTimeChange }}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex gap-1 w-full p-1 items-center justify-between rounded-md border transition-all",
|
||||||
|
"focus-within:outline-0 focus:outline-0 focus:ring-0",
|
||||||
|
"placeholder:text-muted-foreground focus-visible:outline-0 ",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<DateTimeLocalInput />
|
||||||
|
<NaturalLanguageInput
|
||||||
|
placeholder={placeholder}
|
||||||
|
disabled={disabled}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SmartDatetimeInputContext.Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
SmartDatetimeInput.displayName = "DatetimeInput";
|
||||||
|
|
||||||
|
// Make it a standalone component
|
||||||
|
|
||||||
|
const TimePicker = () => {
|
||||||
|
const { value, onValueChange, Time, onTimeChange } = useSmartDateInput();
|
||||||
|
const [activeIndex, setActiveIndex] = React.useState(-1);
|
||||||
|
const timestamp = 15;
|
||||||
|
|
||||||
|
const formateSelectedTime = React.useCallback(
|
||||||
|
(time: string, hour: number, partStamp: number) => {
|
||||||
|
onTimeChange(time);
|
||||||
|
|
||||||
|
const newVal = parseDateTime(value ?? new Date());
|
||||||
|
|
||||||
|
if (!newVal) return;
|
||||||
|
|
||||||
|
newVal.setHours(
|
||||||
|
hour,
|
||||||
|
partStamp === 0 ? parseInt("00") : timestamp * partStamp,
|
||||||
|
);
|
||||||
|
|
||||||
|
// ? refactor needed check if we want to use the new date
|
||||||
|
|
||||||
|
onValueChange(newVal);
|
||||||
|
},
|
||||||
|
[value],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleKeydown = React.useCallback(
|
||||||
|
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (!document) return;
|
||||||
|
|
||||||
|
const moveNext = () => {
|
||||||
|
const nextIndex =
|
||||||
|
activeIndex + 1 > DEFAULT_SIZE - 1 ? 0 : activeIndex + 1;
|
||||||
|
|
||||||
|
const currentElm = document.getElementById(`time-${nextIndex}`);
|
||||||
|
|
||||||
|
currentElm?.focus();
|
||||||
|
|
||||||
|
setActiveIndex(nextIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const movePrev = () => {
|
||||||
|
const prevIndex =
|
||||||
|
activeIndex - 1 < 0 ? DEFAULT_SIZE - 1 : activeIndex - 1;
|
||||||
|
|
||||||
|
const currentElm = document.getElementById(`time-${prevIndex}`);
|
||||||
|
|
||||||
|
currentElm?.focus();
|
||||||
|
|
||||||
|
setActiveIndex(prevIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setElement = () => {
|
||||||
|
const currentElm = document.getElementById(`time-${activeIndex}`);
|
||||||
|
|
||||||
|
if (!currentElm) return;
|
||||||
|
|
||||||
|
currentElm.focus();
|
||||||
|
|
||||||
|
const timeValue = currentElm.textContent ?? "";
|
||||||
|
|
||||||
|
// this should work now haha that hour is what does the trick
|
||||||
|
|
||||||
|
const PM_AM = timeValue.split(" ")[1];
|
||||||
|
const PM_AM_hour = parseInt(timeValue.split(" ")[0].split(":")[0]);
|
||||||
|
const hour =
|
||||||
|
PM_AM === "AM"
|
||||||
|
? PM_AM_hour === 12
|
||||||
|
? 0
|
||||||
|
: PM_AM_hour
|
||||||
|
: PM_AM_hour === 12
|
||||||
|
? 12
|
||||||
|
: PM_AM_hour + 12;
|
||||||
|
|
||||||
|
const part = Math.floor(
|
||||||
|
parseInt(timeValue.split(" ")[0].split(":")[1]) / 15,
|
||||||
|
);
|
||||||
|
|
||||||
|
formateSelectedTime(timeValue, hour, part);
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
const currentElm = document.getElementById(`time-${activeIndex}`);
|
||||||
|
currentElm?.blur();
|
||||||
|
setActiveIndex(-1);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (e.key) {
|
||||||
|
case "ArrowUp":
|
||||||
|
movePrev();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowDown":
|
||||||
|
moveNext();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Escape":
|
||||||
|
reset();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Enter":
|
||||||
|
setElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[activeIndex, formateSelectedTime],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClick = React.useCallback(
|
||||||
|
(hour: number, part: number, PM_AM: string, currentIndex: number) => {
|
||||||
|
formateSelectedTime(
|
||||||
|
`${hour}:${part === 0 ? "00" : timestamp * part} ${PM_AM}`,
|
||||||
|
hour,
|
||||||
|
part,
|
||||||
|
);
|
||||||
|
setActiveIndex(currentIndex);
|
||||||
|
},
|
||||||
|
[formateSelectedTime],
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentTime = React.useMemo(() => {
|
||||||
|
const timeVal = Time.split(" ")[0];
|
||||||
|
return {
|
||||||
|
hours: parseInt(timeVal.split(":")[0]),
|
||||||
|
minutes: parseInt(timeVal.split(":")[1]),
|
||||||
|
};
|
||||||
|
}, [Time]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const getCurrentElementTime = () => {
|
||||||
|
const timeVal = Time.split(" ")[0];
|
||||||
|
const hours = parseInt(timeVal.split(":")[0]);
|
||||||
|
const minutes = parseInt(timeVal.split(":")[1]);
|
||||||
|
const PM_AM = Time.split(" ")[1];
|
||||||
|
|
||||||
|
const formatIndex =
|
||||||
|
PM_AM === "AM" ? hours : hours === 12 ? hours : hours + 12;
|
||||||
|
const formattedHours = formatIndex;
|
||||||
|
|
||||||
|
console.log(formatIndex);
|
||||||
|
|
||||||
|
for (let j = 0; j <= 3; j++) {
|
||||||
|
const diff = Math.abs(j * timestamp - minutes);
|
||||||
|
const selected =
|
||||||
|
PM_AM === (formattedHours >= 12 ? "PM" : "AM") &&
|
||||||
|
(minutes <= 53 ? diff < Math.ceil(timestamp / 2) : diff < timestamp);
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
const trueIndex =
|
||||||
|
activeIndex === -1 ? formattedHours * 4 + j : activeIndex;
|
||||||
|
|
||||||
|
setActiveIndex(trueIndex);
|
||||||
|
|
||||||
|
const currentElm = document.getElementById(`time-${trueIndex}`);
|
||||||
|
currentElm?.scrollIntoView({
|
||||||
|
block: "center",
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getCurrentElementTime();
|
||||||
|
}, [Time, activeIndex]);
|
||||||
|
|
||||||
|
const height = React.useMemo(() => {
|
||||||
|
if (!document) return;
|
||||||
|
const calendarElm = document.getElementById("calendar");
|
||||||
|
if (!calendarElm) return;
|
||||||
|
return calendarElm.style.height;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2 pr-3 py-3 relative ">
|
||||||
|
<h3 className="text-sm font-medium ">Time</h3>
|
||||||
|
<ScrollArea
|
||||||
|
onKeyDown={handleKeydown}
|
||||||
|
className="h-[90%] w-full focus-visible:outline-0 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-0 py-0.5"
|
||||||
|
style={{
|
||||||
|
height,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
className={cn(
|
||||||
|
"flex items-center flex-col gap-1 h-full max-h-56 w-28 px-1 py-0.5",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{Array.from({ length: 24 }).map((_, i) => {
|
||||||
|
const PM_AM = i >= 12 ? "PM" : "AM";
|
||||||
|
const formatIndex = i > 12 ? i % 12 : i === 0 || i === 12 ? 12 : i;
|
||||||
|
return Array.from({ length: 4 }).map((_, part) => {
|
||||||
|
const diff = Math.abs(part * timestamp - currentTime.minutes);
|
||||||
|
|
||||||
|
const trueIndex = i * 4 + part;
|
||||||
|
|
||||||
|
// ? refactor : add the select of the default time on the current device (H:MM)
|
||||||
|
const isSelected =
|
||||||
|
(currentTime.hours === i ||
|
||||||
|
currentTime.hours === formatIndex) &&
|
||||||
|
Time.split(" ")[1] === PM_AM &&
|
||||||
|
(currentTime.minutes <= 53
|
||||||
|
? diff < Math.ceil(timestamp / 2)
|
||||||
|
: diff < timestamp);
|
||||||
|
|
||||||
|
const isSuggested = !value && isSelected;
|
||||||
|
|
||||||
|
const currentValue = `${formatIndex}:${
|
||||||
|
part === 0 ? "00" : timestamp * part
|
||||||
|
} ${PM_AM}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
tabIndex={isSelected ? 0 : -1}
|
||||||
|
id={`time-${trueIndex}`}
|
||||||
|
key={`time-${trueIndex}`}
|
||||||
|
aria-label="currentTime"
|
||||||
|
className={cn(
|
||||||
|
buttonVariants({
|
||||||
|
variant: isSuggested
|
||||||
|
? "secondary"
|
||||||
|
: isSelected
|
||||||
|
? "default"
|
||||||
|
: "outline",
|
||||||
|
}),
|
||||||
|
"h-8 px-3 w-full text-sm focus-visible:outline-0 outline-0 focus-visible:border-0 cursor-default ring-0",
|
||||||
|
)}
|
||||||
|
onClick={() => handleClick(i, part, PM_AM, trueIndex)}
|
||||||
|
onFocus={() => isSuggested && setActiveIndex(trueIndex)}
|
||||||
|
>
|
||||||
|
{currentValue}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const NaturalLanguageInput = React.forwardRef<
|
||||||
|
HTMLInputElement,
|
||||||
|
{
|
||||||
|
placeholder?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
>(({ placeholder, ...props }, ref) => {
|
||||||
|
const { value, onValueChange, Time, onTimeChange } = useSmartDateInput();
|
||||||
|
|
||||||
|
const _placeholder = placeholder ?? 'e.g. "tomorrow at 5pm" or "in 2 hours"';
|
||||||
|
|
||||||
|
const [inputValue, setInputValue] = React.useState<string>("");
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const hour = new Date().getHours();
|
||||||
|
const timeVal = `${
|
||||||
|
hour >= 12 ? hour % 12 : hour
|
||||||
|
}:${new Date().getMinutes()} ${hour >= 12 ? "PM" : "AM"}`;
|
||||||
|
setInputValue(value ? formatDateTime(value) : "");
|
||||||
|
onTimeChange(value ? Time : timeVal);
|
||||||
|
}, [value, Time]);
|
||||||
|
|
||||||
|
const handleParse = React.useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
// parse the date string when the input field loses focus
|
||||||
|
const parsedDateTime = parseDateTime(e.currentTarget.value);
|
||||||
|
if (parsedDateTime) {
|
||||||
|
const PM_AM = parsedDateTime.getHours() >= 12 ? "PM" : "AM";
|
||||||
|
//fix the time format for this value
|
||||||
|
|
||||||
|
const PM_AM_hour = parsedDateTime.getHours();
|
||||||
|
|
||||||
|
const hour =
|
||||||
|
PM_AM_hour > 12
|
||||||
|
? PM_AM_hour % 12
|
||||||
|
: PM_AM_hour === 0 || PM_AM_hour === 12
|
||||||
|
? 12
|
||||||
|
: PM_AM_hour;
|
||||||
|
|
||||||
|
onValueChange(parsedDateTime);
|
||||||
|
setInputValue(formatDateTime(parsedDateTime));
|
||||||
|
onTimeChange(`${hour}:${parsedDateTime.getMinutes()} ${PM_AM}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[value],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleKeydown = React.useCallback(
|
||||||
|
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
switch (e.key) {
|
||||||
|
case "Enter":
|
||||||
|
const parsedDateTime = parseDateTime(e.currentTarget.value);
|
||||||
|
if (parsedDateTime) {
|
||||||
|
const PM_AM = parsedDateTime.getHours() >= 12 ? "PM" : "AM";
|
||||||
|
//fix the time format for this value
|
||||||
|
|
||||||
|
const PM_AM_hour = parsedDateTime.getHours();
|
||||||
|
|
||||||
|
const hour =
|
||||||
|
PM_AM_hour > 12
|
||||||
|
? PM_AM_hour % 12
|
||||||
|
: PM_AM_hour === 0 || PM_AM_hour === 12
|
||||||
|
? 12
|
||||||
|
: PM_AM_hour;
|
||||||
|
|
||||||
|
onValueChange(parsedDateTime);
|
||||||
|
setInputValue(formatDateTime(parsedDateTime));
|
||||||
|
onTimeChange(`${hour}:${parsedDateTime.getMinutes()} ${PM_AM}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[value],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
ref={ref}
|
||||||
|
type="text"
|
||||||
|
placeholder={_placeholder}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => setInputValue(e.currentTarget.value)}
|
||||||
|
onKeyDown={handleKeydown}
|
||||||
|
onBlur={handleParse}
|
||||||
|
className={cn("px-2 mr-0.5 flex-1 border-none h-8 rounded", inputBase)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
NaturalLanguageInput.displayName = "NaturalLanguageInput";
|
||||||
|
|
||||||
|
type DateTimeLocalInputProps = {} & CalendarProps;
|
||||||
|
|
||||||
|
const DateTimeLocalInput = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: DateTimeLocalInputProps) => {
|
||||||
|
const { value, onValueChange, Time } = useSmartDateInput();
|
||||||
|
|
||||||
|
const formateSelectedDate = React.useCallback(
|
||||||
|
(
|
||||||
|
date: Date | undefined,
|
||||||
|
selectedDate: Date,
|
||||||
|
m: ActiveModifiers,
|
||||||
|
e: React.MouseEvent,
|
||||||
|
) => {
|
||||||
|
const parsedDateTime = parseDateTime(selectedDate);
|
||||||
|
|
||||||
|
if (parsedDateTime) {
|
||||||
|
parsedDateTime.setHours(
|
||||||
|
parseInt(Time.split(":")[0]),
|
||||||
|
parseInt(Time.split(":")[1]),
|
||||||
|
);
|
||||||
|
onValueChange(parsedDateTime);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[value, Time],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant={"outline"}
|
||||||
|
size={"icon"}
|
||||||
|
className={cn(
|
||||||
|
"size-9 flex items-center justify-center font-normal",
|
||||||
|
!value && "text-muted-foreground",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CalendarIcon className="size-4" />
|
||||||
|
<span className="sr-only">calender</span>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto p-0" sideOffset={8}>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<Calendar
|
||||||
|
{...props}
|
||||||
|
id={"calendar"}
|
||||||
|
className={cn("peer flex justify-end", inputBase, className)}
|
||||||
|
mode="single"
|
||||||
|
selected={value}
|
||||||
|
onSelect={formateSelectedDate}
|
||||||
|
initialFocus
|
||||||
|
/>
|
||||||
|
<TimePicker />
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
DateTimeLocalInput.displayName = "DateTimeLocalInput";
|
||||||
|
|
@ -0,0 +1,306 @@
|
||||||
|
import {
|
||||||
|
INVALID,
|
||||||
|
ParseContext,
|
||||||
|
ParseInput,
|
||||||
|
ParseReturnType,
|
||||||
|
ParseStatus,
|
||||||
|
RawCreateParams,
|
||||||
|
ZodIssueCode,
|
||||||
|
ZodParsedType,
|
||||||
|
ZodType,
|
||||||
|
ZodTypeDef,
|
||||||
|
addIssueToContext,
|
||||||
|
} from "zod";
|
||||||
|
|
||||||
|
export type ZodDecimalCheck =
|
||||||
|
| { kind: "precision"; value: number; message?: string }
|
||||||
|
| { kind: "wholeNumber"; value: number; message?: string }
|
||||||
|
| { kind: "min"; value: number; inclusive: boolean; message?: string }
|
||||||
|
| { kind: "max"; value: number; inclusive: boolean; message?: string }
|
||||||
|
| { kind: "finite"; message?: string };
|
||||||
|
|
||||||
|
const zodDecimalKind = "ZodDecimal";
|
||||||
|
|
||||||
|
export interface ZodDecimalDef extends ZodTypeDef {
|
||||||
|
checks: ZodDecimalCheck[];
|
||||||
|
typeName: typeof zodDecimalKind;
|
||||||
|
coerce: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const precisionRegex = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export class ZodDecimal extends ZodType<number, ZodDecimalDef, any> {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
_parse(input: ParseInput): ParseReturnType<number> {
|
||||||
|
// detect decimal js object
|
||||||
|
if (
|
||||||
|
input.data !== null &&
|
||||||
|
typeof input.data === "object" &&
|
||||||
|
"toNumber" in input.data
|
||||||
|
) {
|
||||||
|
input.data = input.data.toNumber();
|
||||||
|
}
|
||||||
|
if (this._def.coerce) {
|
||||||
|
input.data = Number(input.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedType = this._getType(input);
|
||||||
|
if (parsedType !== ZodParsedType.number) {
|
||||||
|
const ctx = this._getOrReturnCtx(input);
|
||||||
|
addIssueToContext(ctx, {
|
||||||
|
code: ZodIssueCode.invalid_type,
|
||||||
|
expected: ZodParsedType.number,
|
||||||
|
received: ctx.parsedType,
|
||||||
|
});
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctx: undefined | ParseContext = undefined;
|
||||||
|
const status = new ParseStatus();
|
||||||
|
|
||||||
|
for (const check of this._def.checks) {
|
||||||
|
if (check.kind === "precision") {
|
||||||
|
const parts = input.data.toString().match(precisionRegex);
|
||||||
|
const decimals = Math.max(
|
||||||
|
(parts[1] ? parts[1].length : 0) -
|
||||||
|
(parts[2] ? parseInt(parts[2], 10) : 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (decimals > check.value) {
|
||||||
|
ctx = this._getOrReturnCtx(input, ctx);
|
||||||
|
addIssueToContext(ctx, {
|
||||||
|
code: ZodIssueCode.custom,
|
||||||
|
message: check.message,
|
||||||
|
params: {
|
||||||
|
precision: check.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
status.dirty();
|
||||||
|
}
|
||||||
|
} else if (check.kind === "wholeNumber") {
|
||||||
|
const wholeNumber = input.data.toString().split(".")[0];
|
||||||
|
const tooLong = wholeNumber.length > check.value;
|
||||||
|
|
||||||
|
if (tooLong) {
|
||||||
|
ctx = this._getOrReturnCtx(input, ctx);
|
||||||
|
addIssueToContext(ctx, {
|
||||||
|
code: ZodIssueCode.custom,
|
||||||
|
message: check.message,
|
||||||
|
params: {
|
||||||
|
wholeNumber: check.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
status.dirty();
|
||||||
|
}
|
||||||
|
} else if (check.kind === "min") {
|
||||||
|
const tooSmall = check.inclusive
|
||||||
|
? input.data < check.value
|
||||||
|
: input.data <= check.value;
|
||||||
|
if (tooSmall) {
|
||||||
|
ctx = this._getOrReturnCtx(input, ctx);
|
||||||
|
addIssueToContext(ctx, {
|
||||||
|
code: ZodIssueCode.too_small,
|
||||||
|
minimum: check.value,
|
||||||
|
type: "number",
|
||||||
|
inclusive: check.inclusive,
|
||||||
|
exact: false,
|
||||||
|
message: check.message,
|
||||||
|
});
|
||||||
|
status.dirty();
|
||||||
|
}
|
||||||
|
} else if (check.kind === "max") {
|
||||||
|
const tooBig = check.inclusive
|
||||||
|
? input.data > check.value
|
||||||
|
: input.data >= check.value;
|
||||||
|
if (tooBig) {
|
||||||
|
ctx = this._getOrReturnCtx(input, ctx);
|
||||||
|
addIssueToContext(ctx, {
|
||||||
|
code: ZodIssueCode.too_big,
|
||||||
|
maximum: check.value,
|
||||||
|
type: "number",
|
||||||
|
inclusive: check.inclusive,
|
||||||
|
exact: false,
|
||||||
|
message: check.message,
|
||||||
|
});
|
||||||
|
status.dirty();
|
||||||
|
}
|
||||||
|
} else if (check.kind === "finite") {
|
||||||
|
if (!Number.isFinite(input.data)) {
|
||||||
|
ctx = this._getOrReturnCtx(input, ctx);
|
||||||
|
addIssueToContext(ctx, {
|
||||||
|
code: ZodIssueCode.not_finite,
|
||||||
|
message: check.message,
|
||||||
|
});
|
||||||
|
status.dirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { status: status.value, value: input.data };
|
||||||
|
}
|
||||||
|
|
||||||
|
static create = (
|
||||||
|
params?: RawCreateParams & { coerce?: true }
|
||||||
|
): ZodDecimal => {
|
||||||
|
return new ZodDecimal({
|
||||||
|
checks: [],
|
||||||
|
typeName: zodDecimalKind,
|
||||||
|
coerce: params?.coerce ?? false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
protected setLimit(
|
||||||
|
kind: "min" | "max",
|
||||||
|
value: number,
|
||||||
|
inclusive: boolean,
|
||||||
|
message?: string
|
||||||
|
): ZodDecimal {
|
||||||
|
return new ZodDecimal({
|
||||||
|
...this._def,
|
||||||
|
checks: [
|
||||||
|
...this._def.checks,
|
||||||
|
{
|
||||||
|
kind,
|
||||||
|
value,
|
||||||
|
inclusive,
|
||||||
|
message,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_addCheck(check: ZodDecimalCheck): ZodDecimal {
|
||||||
|
return new ZodDecimal({
|
||||||
|
...this._def,
|
||||||
|
checks: [...this._def.checks, check],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lte(value: number, message?: string): ZodDecimal {
|
||||||
|
return this.setLimit("max", value, true, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
lt(value: number, message?: string): ZodDecimal {
|
||||||
|
return this.setLimit("max", value, false, message);
|
||||||
|
}
|
||||||
|
max = this.lte;
|
||||||
|
|
||||||
|
gt(value: number, message?: string): ZodDecimal {
|
||||||
|
return this.setLimit("min", value, false, message);
|
||||||
|
}
|
||||||
|
gte(value: number, message?: string): ZodDecimal {
|
||||||
|
return this.setLimit("min", value, true, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
min = this.gte;
|
||||||
|
|
||||||
|
precision(value: number, message?: string): ZodDecimal {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "precision",
|
||||||
|
value,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
wholeNumber(value: number, message?: string): ZodDecimal {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "wholeNumber",
|
||||||
|
value,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get minValue() {
|
||||||
|
let min: number | null = null;
|
||||||
|
for (const ch of this._def.checks) {
|
||||||
|
if (ch.kind === "min") {
|
||||||
|
if (min === null || ch.value > min) min = ch.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
get maxValue() {
|
||||||
|
let max: number | null = null;
|
||||||
|
for (const ch of this._def.checks) {
|
||||||
|
if (ch.kind === "max") {
|
||||||
|
if (max === null || ch.value < max) max = ch.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
positive(message?: string) {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "min",
|
||||||
|
value: 0,
|
||||||
|
inclusive: false,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
negative(message?: string) {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "max",
|
||||||
|
value: 0,
|
||||||
|
inclusive: false,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
nonpositive(message?: string) {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "max",
|
||||||
|
value: 0,
|
||||||
|
inclusive: true,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
nonnegative(message?: string) {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "min",
|
||||||
|
value: 0,
|
||||||
|
inclusive: true,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
finite(message?: string) {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "finite",
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
safe(message?: string) {
|
||||||
|
return this._addCheck({
|
||||||
|
kind: "min",
|
||||||
|
inclusive: true,
|
||||||
|
value: Number.MIN_SAFE_INTEGER,
|
||||||
|
message,
|
||||||
|
})._addCheck({
|
||||||
|
kind: "max",
|
||||||
|
inclusive: true,
|
||||||
|
value: Number.MAX_SAFE_INTEGER,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get isFinite() {
|
||||||
|
let max: number | null = null,
|
||||||
|
min: number | null = null;
|
||||||
|
for (const ch of this._def.checks) {
|
||||||
|
if (ch.kind === "finite") {
|
||||||
|
return true;
|
||||||
|
} else if (ch.kind === "min") {
|
||||||
|
if (min === null || ch.value > min) min = ch.value;
|
||||||
|
} else if (ch.kind === "max") {
|
||||||
|
if (max === null || ch.value < max) max = ch.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Number.isFinite(min) && Number.isFinite(max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
export const zodDecimal = ZodDecimal.create;
|
||||||
Loading…
Reference in New Issue