From bc593cd12fbb7ffab0e939a30586ba736002ec24 Mon Sep 17 00:00:00 2001 From: renzonj Date: Tue, 27 Jun 2023 13:23:27 +0800 Subject: [PATCH 1/5] testing --- README.md | 2 +- ...427114000_connect_read_pending_users_capabilities.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2d250f59..9b6d749c 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Screnshots: https://cms.demo.klaudsol.app image - +testing diff --git a/db/migrations/20230427114000_connect_read_pending_users_capabilities.json b/db/migrations/20230427114000_connect_read_pending_users_capabilities.json index 557f2d99..efa6ce52 100644 --- a/db/migrations/20230427114000_connect_read_pending_users_capabilities.json +++ b/db/migrations/20230427114000_connect_read_pending_users_capabilities.json @@ -1,11 +1,11 @@ { "up": [ - "REPLACE INTO group_capabilities (group_id, capabilities_id) VALUES", - "(1, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true)),", - "(2, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true));" + "INSERT INTO group_capabilities (group_id, capabilities_id) VALUES", + "(1, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true LIMIT 1)),", + "(2, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true LIMIT 1));" ], "down":[ "DELETE FROM group_capabilities WHERE group_id IN (1, 2) ", - "AND capabilities_id = (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true);" + "AND capabilities_id IN (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true);" ] } From 8901aebeed4f2d3e418a2f058c47543ed4750318 Mon Sep 17 00:00:00 2001 From: renzonj Date: Tue, 27 Jun 2023 14:20:16 +0800 Subject: [PATCH 2/5] testing 2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b6d749c..0758b384 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,6 @@ Screnshots: https://cms.demo.klaudsol.app testing - +testing 2 From 3e12998008c800f39871fd4ef9146cb756f93e52 Mon Sep 17 00:00:00 2001 From: renzonj Date: Tue, 27 Jun 2023 14:42:41 +0800 Subject: [PATCH 3/5] testing --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0758b384..3deaeb82 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Screnshots: https://cms.demo.klaudsol.app image -testing -testing 2 +sample + From e946712967d679ad737a4bd600ef14067d6ac1cb Mon Sep 17 00:00:00 2001 From: renzonj Date: Mon, 3 Jul 2023 13:48:46 +0800 Subject: [PATCH 4/5] testing --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3deaeb82..921fe43e 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Screnshots: https://cms.demo.klaudsol.app image -sample +Testing..... From d4cfebc7426f42510f72db7be01f6dcbc37024e3 Mon Sep 17 00:00:00 2001 From: renzonj Date: Mon, 3 Jul 2023 14:30:11 +0800 Subject: [PATCH 5/5] add DateTime Attribute Type --- backend/models/core/Entity.js | 25 +++++++-- components/EntityAttributeValue.js | 4 +- components/attribute_types/AttributeType.js | 1 + .../attribute_types/AttributeTypeFactory.js | 3 ++ .../attribute_types/DateTimeAttributeType.js | 51 +++++++++++++++++++ components/cmsTypes.js | 4 +- components/renderers/admin/AdminRenderer.js | 4 +- constants/index.js | 2 +- ...nnect_read_pending_users_capabilities.json | 10 ++-- package.json | 2 +- styles/klaudsolcms.scss | 18 +++++++ yarn.lock | 8 +-- 12 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 components/attribute_types/DateTimeAttributeType.js diff --git a/backend/models/core/Entity.js b/backend/models/core/Entity.js index 74d87558..f706c57f 100644 --- a/backend/models/core/Entity.js +++ b/backend/models/core/Entity.js @@ -256,14 +256,21 @@ class Entity { ? { booleanValue: entry[attributeName] } : { isNull: true }, }, + { + name: "value_datetime", + value: + attributeType == "datetime" + ? { stringValue: entry[attributeName] } + : { isNull: true }, + }, ], ]; }, []); //Insert Values by batch const insertValuesBatchSQL = `INSERT INTO \`values\`(entity_id, attribute_id, - value_string, value_long_string, value_double, value_boolean - ) VALUES (:entity_id, :attribute_id, :value_string, :value_long_string, :value_double, :value_boolean) + value_string, value_long_string, value_datetime, value_double, value_boolean + ) VALUES (:entity_id, :attribute_id, :value_string, :value_long_string, :value_datetime, :value_double, :value_boolean) `; await db.batchExecuteStatement(insertValuesBatchSQL, valueBatchParams); @@ -449,6 +456,13 @@ class Entity { ? { booleanValue: entries[attributeName] } : { isNull: true }, }, + { + name: "value_datetime", + value: + attributeType == "datetime" + ? { stringValue: entries[attributeName] } + : { isNull: true }, + }, ], ]; }, []); @@ -484,8 +498,8 @@ class Entity { if (nonExistingVal.length) { const insertValuesBatchSQL = `INSERT INTO \`values\`(entity_id, attribute_id, - value_string, value_long_string, value_double, value_boolean - ) VALUES (:entity_id, :attribute_id, :value_string, :value_long_string, :value_double, :value_boolean) + value_string, value_long_string, value_datetime, value_double, value_boolean + ) VALUES (:entity_id, :attribute_id, :value_string, :value_long_string, :value_datetime, :value_double, :value_boolean) `; await db.batchExecuteStatement(insertValuesBatchSQL, nonExistingVal); @@ -496,6 +510,7 @@ class Entity { const updateValuesBatchSQL = `UPDATE \`values\` SET value_string = :value_string, value_long_string = :value_long_string, + value_datetime = :value_datetime, value_double = :value_double, value_boolean = :value_boolean WHERE entity_id = :entity_id AND attribute_id = :attribute_id @@ -508,4 +523,4 @@ class Entity { } } -export default Entity; +export default Entity; \ No newline at end of file diff --git a/components/EntityAttributeValue.js b/components/EntityAttributeValue.js index 660eb797..85ecd712 100644 --- a/components/EntityAttributeValue.js +++ b/components/EntityAttributeValue.js @@ -42,6 +42,8 @@ const formatImage = (key) => { case 'float': //TODO: Find a more accurate representation of float return Number(item.value_double); + case 'datetime': + return item.value_datetime; case 'custom': const CustomAttributeType = plugin(item.attributes_custom_name); const customAttributeType = new CustomAttributeType({ @@ -56,4 +58,4 @@ const formatImage = (key) => { return customAttributeType.toApi(); } - } + } \ No newline at end of file diff --git a/components/attribute_types/AttributeType.js b/components/attribute_types/AttributeType.js index ddd051e4..394ed142 100644 --- a/components/attribute_types/AttributeType.js +++ b/components/attribute_types/AttributeType.js @@ -12,6 +12,7 @@ export default class AttributeType { static TEXT_CMS_TYPE = 'text'; static TEXTAREA_CMS_TYPE = 'textarea'; static RICH_TEXT_CMS_TYPE = 'rich-text'; + static DATETIME_CMS_TYPE = 'datetime'; static CUSTOM = 'custom'; diff --git a/components/attribute_types/AttributeTypeFactory.js b/components/attribute_types/AttributeTypeFactory.js index 1f11ca4a..c8a30ab7 100644 --- a/components/attribute_types/AttributeTypeFactory.js +++ b/components/attribute_types/AttributeTypeFactory.js @@ -4,6 +4,7 @@ import TextareaAttributeType from "@/components/attribute_types/TextareaAttribut import LegacyAttributeType from '@/components/attribute_types/LegacyAttributeType'; import { plugin } from '@/components/plugin/plugin'; import RichTextAttributeType from '@/components/attribute_types/RichTextAttributeType'; +import DateTimeAttributeType from '@/components/attribute_types/DateTimeAttributeType'; export default class AttributeTypeFactory { static create({data, metadata}) { @@ -14,6 +15,8 @@ export default class AttributeTypeFactory { return new TextareaAttributeType({data, metadata}); case AttributeType.RICH_TEXT_CMS_TYPE: return new RichTextAttributeType({data, metadata}); + case AttributeType.DATETIME_CMS_TYPE: + return new DateTimeAttributeType({data, metadata}); case AttributeType.CUSTOM: const CustomAttributeType = plugin(metadata.custom_name); return new CustomAttributeType({data, metadata}); diff --git a/components/attribute_types/DateTimeAttributeType.js b/components/attribute_types/DateTimeAttributeType.js new file mode 100644 index 00000000..371045c8 --- /dev/null +++ b/components/attribute_types/DateTimeAttributeType.js @@ -0,0 +1,51 @@ +import AttributeType from '@/components/attribute_types/AttributeType'; +import { useFormikContext, useField } from "formik"; +import { useState, useEffect } from 'react'; +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; +import moment from 'moment'; + +const DateTimeAttributeReadOnlyComponent = ({ text }) => { + const parsedDate = new Date(text); + const formattedDate = moment(parsedDate).format('MMM. D, YYYY - hh:mm A'); + return <>{formattedDate}; +}; + +const DateTimeAttributeEditableComponent = ({ name }) => { + const { setFieldValue } = useFormikContext(); + const [{ value }] = useField(name); + const [selectedDate, setSelectedDate] = useState(value ? new Date(value) : new Date()); // Set initial selected date to today + + useEffect(() => { + if (selectedDate) { + const formattedDate = moment(selectedDate).format('YYYY-MM-DD HH:mm'); + setFieldValue(name, formattedDate); + } else { + setFieldValue(name, null); + } + }, [selectedDate, name, setFieldValue]); + + const handleDateChange = (date) => { + setSelectedDate(date); + }; + + return ( + + ); +}; + +export default class DateTimeAttributeType extends AttributeType { + readOnlyComponent() { + return DateTimeAttributeReadOnlyComponent; + } + + editableComponent() { + return DateTimeAttributeEditableComponent; + } +} \ No newline at end of file diff --git a/components/cmsTypes.js b/components/cmsTypes.js index 8df91642..e226f092 100644 --- a/components/cmsTypes.js +++ b/components/cmsTypes.js @@ -13,7 +13,8 @@ export const CMS_TYPES = { PASSWORD: "password", CHECKBOX: "checkbox", CUSTOM: "custom", - RICH_TEXT: "rich-text" + RICH_TEXT: "rich-text", + DATETIME: "datetime" }; // resources types @@ -43,4 +44,3 @@ export const resourceValueTypes = [ "value_double", "value_boolean", ]; - diff --git a/components/renderers/admin/AdminRenderer.js b/components/renderers/admin/AdminRenderer.js index f3b10570..36db5220 100644 --- a/components/renderers/admin/AdminRenderer.js +++ b/components/renderers/admin/AdminRenderer.js @@ -11,6 +11,7 @@ import VideoRenderer from "./VideoRenderer"; import BooleanRenderer from "./BooleanRenderer"; import { plugin } from "@/components/plugin/plugin"; import RichTextAttributeType from "@/components/attribute_types/RichTextAttributeType"; +import DateTimeAttributeType from "@/components/attribute_types/DateTimeAttributeType"; import AttributeTypeFactory from "@/components/attribute_types/AttributeTypeFactory"; const AdminRenderer = ({ type, ...params }) => { @@ -35,6 +36,7 @@ const AdminRenderer = ({ type, ...params }) => { case CMS_TYPES.BOOLEAN: return ; case CMS_TYPES.RICH_TEXT: + case CMS_TYPES.DATETIME: case CMS_TYPES.CUSTOM: const attributeType = AttributeTypeFactory.create({metadata: {type, custom_name: params.customName, id: params.id}}); const Component = attributeType.editableComponent(); @@ -44,4 +46,4 @@ const AdminRenderer = ({ type, ...params }) => { } }; -export default AdminRenderer; +export default AdminRenderer; \ No newline at end of file diff --git a/constants/index.js b/constants/index.js index a880c284..372fd078 100644 --- a/constants/index.js +++ b/constants/index.js @@ -7,6 +7,7 @@ export const inputValues = [ { value: "gallery", option: "Gallery" }, { value: "float", option: "Number" }, { value: "video", option: "Video" }, + { value: "datetime", option: "DateTime" }, { value: "boolean", option: "Boolean" }, { value: "custom", option: "Custom" } ]; @@ -44,4 +45,3 @@ export const operators = { }; export const slugTooltipText = "Slugs are the URL-friendly names of your contents. You can access the contens in your API via their numerical ID (e.g. /api/articles/12) or their slug (e.g. /api/articles/my-first-blog-post)"; - diff --git a/db/migrations/20230427114000_connect_read_pending_users_capabilities.json b/db/migrations/20230427114000_connect_read_pending_users_capabilities.json index efa6ce52..1f427b10 100644 --- a/db/migrations/20230427114000_connect_read_pending_users_capabilities.json +++ b/db/migrations/20230427114000_connect_read_pending_users_capabilities.json @@ -1,11 +1,11 @@ { "up": [ - "INSERT INTO group_capabilities (group_id, capabilities_id) VALUES", - "(1, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true LIMIT 1)),", - "(2, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true LIMIT 1));" + "REPLACE INTO group_capabilities (group_id, capabilities_id) VALUES", + "(1, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true)),", + "(2, (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true));" ], "down":[ "DELETE FROM group_capabilities WHERE group_id IN (1, 2) ", - "AND capabilities_id IN (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true);" + "AND capabilities_id = (SELECT id FROM capabilities WHERE name = 'read_pending_users' AND is_system_supplied = true);" ] -} +} \ No newline at end of file diff --git a/package.json b/package.json index f5e70ae5..f9e63916 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "react-component-export-image": "^1.0.6", "react-confirm-alert": "2.0.2", "react-csv-downloader": "^2.8.0", - "react-datepicker": "^4.8.0", + "react-datepicker": "^4.15.0", "react-dom": "^18.2.0", "react-hook-form": "^7.33.0", "react-icons": "^4.3.1", diff --git a/styles/klaudsolcms.scss b/styles/klaudsolcms.scss index cd635cc4..cf20565f 100644 --- a/styles/klaudsolcms.scss +++ b/styles/klaudsolcms.scss @@ -1398,3 +1398,21 @@ $onFocus: #323C4E; font-weight: 590; } } + +/** +====================================================== + MODIFY DATE PICKER DESIGN +====================================================== +**/ +.react-datepicker__input-container input { + padding: 8px; + border-radius: 5px; + border: 1px solid #ccc !important; +} +// change the selected date color +.react-datepicker__day--selected, .react-datepicker__time-list-item--selected { + background-color: #467286 !important; +} +.react-datepicker__time-container { + overflow: hidden; +} diff --git a/yarn.lock b/yarn.lock index 4d0d8c4c..d88bf603 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4294,10 +4294,10 @@ react-csv-downloader@^2.8.0: dependencies: file-saver "^2.0.2" -react-datepicker@^4.8.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.11.0.tgz#40e73b4729a284ed206fdb322b8e84eb566e11a3" - integrity sha512-50n93o7mQwBEhg05tbopjFKgs8qgi8VBCAOMC4VqrKut72eAjESc/wXS/k5hRtnP0oe2FCGw7MJuIwh37wuXOw== +react-datepicker@^4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.15.0.tgz#489834773fbcf87852273b4642f0c5bd3811cef7" + integrity sha512-kysEqVv6wRQkmAyn0wJi4Xx+JjBPBtXWfQSfh6sR3wdzZX1/LjYTPmaurnVI6ao177ecompg8ze7NCgtEGW78A== dependencies: "@popperjs/core" "^2.9.2" classnames "^2.2.6"