diff --git a/backend/package.json b/backend/package.json index 1d55190..f9c9b6d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -21,8 +21,8 @@ "bcryptjs": "^2.4.3", "cookie-parser": "^1.4.5", "cors": "^2.8.5", - "date-fns": "^2.16.1", - "date-fns-tz": "^1.3.4", + "date-fns": "^2.30.0", + "date-fns-tz": "^1.3.8", "dotenv": "^8.2.0", "express": "^4.17.1", "express-async-errors": "^3.1.1", diff --git a/backend/src/controllers/SettingController.ts b/backend/src/controllers/SettingController.ts index c8cb940..938acf8 100644 --- a/backend/src/controllers/SettingController.ts +++ b/backend/src/controllers/SettingController.ts @@ -14,21 +14,24 @@ export const index = async (req: Request, res: Response): Promise => { // } const settings = await ListSettingsService(); - const outBusinessHours = await SettingTicket.findOne({ - where: { key: "outBusinessHours" } - }); - const ticketExpiration = await SettingTicket.findOne({ - where: { key: "ticketExpiration" } - }); - return res.status(200).json({ settings, outBusinessHours, ticketExpiration }); + const config = await SettingTicket.findAll(); + + return res.status(200).json({ settings, config }); }; export const updateTicketSettings = async ( req: Request, res: Response ): Promise => { - const { outBusinessHours, ticketExpiration } = req.body; + const { + outBusinessHours, + ticketExpiration, + weekend, + saturday, + sunday, + holiday + } = req.body; if (outBusinessHours && Object.keys(outBusinessHours).length > 0) { await updateSettingTicket({ @@ -44,7 +47,44 @@ export const updateTicketSettings = async ( }); } - return res.status(200).json({ outBusinessHours, ticketExpiration }); + if (weekend && Object.keys(weekend).length > 0) { + await updateSettingTicket({ + ...weekend, + key: "weekend" + }); + } + + if (saturday && Object.keys(saturday).length > 0) { + await updateSettingTicket({ + ...saturday, + key: "saturday" + }); + } + + if (sunday && Object.keys(sunday).length > 0) { + await updateSettingTicket({ + ...sunday, + key: "sunday" + }); + } + + if (holiday && Object.keys(holiday).length > 0) { + await updateSettingTicket({ + ...holiday, + key: "holiday" + }); + } + + return res + .status(200) + .json({ + outBusinessHours, + ticketExpiration, + weekend, + saturday, + sunday, + holiday + }); }; export const update = async ( diff --git a/backend/src/database/seeds/20230808210411-add-setting-ticket-weekend.ts b/backend/src/database/seeds/20230808210411-add-setting-ticket-weekend.ts new file mode 100644 index 0000000..8ffa27d --- /dev/null +++ b/backend/src/database/seeds/20230808210411-add-setting-ticket-weekend.ts @@ -0,0 +1,34 @@ +import { QueryInterface } from "sequelize" + +module.exports = { + up: (queryInterface: QueryInterface) => { + return queryInterface.bulkInsert( + "SettingTickets", + [ + { + message: "", + startTime: new Date(), + endTime: new Date(), + value: "disabled", + key: "saturday", + createdAt: new Date(), + updatedAt: new Date() + }, + { + message: "", + startTime: new Date(), + endTime: new Date(), + value: "disabled", + key: "sunday", + createdAt: new Date(), + updatedAt: new Date() + } + ], + {} + ); + }, + + down: (queryInterface: QueryInterface) => { + return queryInterface.bulkDelete("SettingTickets", {}) + } +} diff --git a/backend/src/database/seeds/20230808210840-add-setting-ticket-holiday.ts b/backend/src/database/seeds/20230808210840-add-setting-ticket-holiday.ts new file mode 100644 index 0000000..efd73ce --- /dev/null +++ b/backend/src/database/seeds/20230808210840-add-setting-ticket-holiday.ts @@ -0,0 +1,25 @@ +import { QueryInterface } from "sequelize"; + +module.exports = { + up: (queryInterface: QueryInterface) => { + return queryInterface.bulkInsert( + "SettingTickets", + [ + { + message: "", + startTime: new Date(), + endTime: new Date(), + value: "disabled", + key: "holiday", + createdAt: new Date(), + updatedAt: new Date() + }, + ], + {} + ); + }, + + down: (queryInterface: QueryInterface) => { + return queryInterface.bulkDelete("SettingTickets", {}); + } +}; diff --git a/backend/src/database/seeds/20230809085716-add-setting-ticket-weekend-enable.ts b/backend/src/database/seeds/20230809085716-add-setting-ticket-weekend-enable.ts new file mode 100644 index 0000000..48fd2db --- /dev/null +++ b/backend/src/database/seeds/20230809085716-add-setting-ticket-weekend-enable.ts @@ -0,0 +1,25 @@ +import { QueryInterface } from "sequelize"; + +module.exports = { + up: (queryInterface: QueryInterface) => { + return queryInterface.bulkInsert( + "SettingTickets", + [ + { + message: "", + startTime: new Date(), + endTime: new Date(), + value: "disabled", + key: "weekend", + createdAt: new Date(), + updatedAt: new Date() + } + ], + {} + ); + }, + + down: (queryInterface: QueryInterface) => { + return queryInterface.bulkDelete("SettingTickets", {}); + } +}; diff --git a/backend/src/helpers/AutoCloseTickets.ts b/backend/src/helpers/AutoCloseTickets.ts index 2948035..4074c37 100644 --- a/backend/src/helpers/AutoCloseTickets.ts +++ b/backend/src/helpers/AutoCloseTickets.ts @@ -39,14 +39,14 @@ const AutoCloseTickets = async () => { const seconds = timeStringToSeconds(startTime.fullTime); - console.log("Ticket seconds: ", seconds); + // console.log("Ticket seconds: ", seconds); let tickets: any = await ListTicketTimeLife({ timeseconds: seconds, status: "open" }); - console.log("tickets: ", tickets); + // console.log("tickets: ", tickets); for (let i = 0; i < tickets.length; i++) { diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 426b119..d5dfae9 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -11,10 +11,15 @@ import { format as _format, isWithinInterval, parse, - subMinutes + subMinutes, + isSaturday, + isSunday, + parseISO } from "date-fns"; import ptBR from "date-fns/locale/pt-BR"; +import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz"; + import { Contact as WbotContact, Message as WbotMessage, @@ -596,13 +601,103 @@ const handleMessage = async (msg: any, wbot: any): Promise => { //Habilitar esse caso queira usar o bot // const botInfo = await BotIsOnQueue('botqueue') - // const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 }; - + // const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 }; if (msg && !msg.fromMe && ticket.status == "pending") { await setMessageAsRead(ticket); } + // MESSAGE TO HOLIDAY + const holiday = await SettingTicket.findOne({ + where: { key: "holiday" } + }); + + if ( + holiday && + holiday.value == "enabled" && + holiday.message?.trim()?.length > 0 + ) { + const startTime = splitDateTime( + new Date( + _format(new Date(holiday.startTime), "yyyy-MM-dd HH:mm:ss", { + locale: ptBR + }) + ) + ); + + const currentDate = splitDateTime( + new Date( + _format(new Date(), "yyyy-MM-dd HH:mm:ss", { + locale: ptBR + }) + ) + ); + + if (msg.fromMe && holiday && holiday.message.trim() == msg.body.trim()) { + console.log("HOLIDAY DAY"); + return; + } + + if (currentDate.fullDate == startTime.fullDate) { + botSendMessage(ticket, holiday.message); + return; + } + } + + // MESSAGES TO SATURDAY OR SUNDAY + const weekend = await SettingTicket.findOne({ + where: { key: "weekend" } + }); + + if ( + weekend && + weekend.value == "enabled" && + weekend.message?.trim()?.length > 0 + ) { + if (msg.fromMe && weekend.message.trim() == msg.body.trim()) { + console.log("SATURDAY OR SUNDAY DATE"); + return; + } + + // Specify your desired timezone + const brazilTimeZone = "America/Sao_Paulo"; + + const currentDateUtc = new Date(); + + // Convert UTC date to Brazil time zone + const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone); + + // Format the date using the desired format + const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX"); + + const parsedDate = parseISO(formattedDate); + + // Convert parsed date to Brazil time zone + const localDate = utcToZonedTime(parsedDate, brazilTimeZone); + + // Check if it's Saturday or Sunday + if (isSaturday(localDate)) { + const saturday = await SettingTicket.findOne({ + where: { key: "saturday" } + }); + + if (saturday && saturday.value == "enabled") { + botSendMessage(ticket, weekend.message); + return; + } + } else if (isSunday(localDate)) { + const sunday = await SettingTicket.findOne({ + where: { key: "sunday" } + }); + + if (sunday && sunday.value == "enabled") { + botSendMessage(ticket, weekend.message); + return; + } + } + } + + // MESSAGE TO BUSINESS TIME const businessTime: any = await BusinessTime(); if ( diff --git a/frontend/package.json b/frontend/package.json index 50b81dc..681cd4b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,13 +4,13 @@ "private": true, "dependencies": { "@date-io/date-fns": "^1.3.13", - "@emotion/react": "^11.7.1", - "@emotion/styled": "^11.6.0", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", "@material-ui/core": "^4.12.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.56", "@material-ui/pickers": "^3.3.10", - "@mui/material": "^5.3.0", + "@mui/material": "^5.14.4", "@mui/x-data-grid": "^5.3.0", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.0.4", @@ -31,6 +31,7 @@ "react": "^17.0.2", "react-color": "^2.19.3", "react-csv": "^2.2.2", + "react-datepicker": "^4.16.0", "react-dom": "^17.0.2", "react-modal-image": "^2.5.0", "react-router-dom": "^5.2.0", diff --git a/frontend/src/components/ConfigModal/index.js b/frontend/src/components/ConfigModal/index.js index 7c08118..2187fdc 100644 --- a/frontend/src/components/ConfigModal/index.js +++ b/frontend/src/components/ConfigModal/index.js @@ -4,15 +4,16 @@ import { Formik, Form, Field, } from 'formik' import { toast } from 'react-toastify' import { makeStyles } from '@material-ui/core/styles' -import { green } from '@material-ui/core/colors' +import { green } from '@material-ui/core/colors' -import { TimePicker } from 'formik-material-ui-pickers' +import { TimePicker, DatePicker } from 'formik-material-ui-pickers' import DateFnsUtils from '@date-io/date-fns' import ptBrLocale from "date-fns/locale/pt-BR" + import { MuiPickersUtilsProvider, } from '@material-ui/pickers' @@ -73,10 +74,17 @@ const ConfigModal = ({ open, onClose, change }) => { startTimeBus: new Date(), endTimeBus: new Date(), messageBus: '', - businessTimeEnalbe: false, + businessTimeEnable: false, ticketTimeExpiration: new Date(), ticketExpirationMsg: '', ticketExpirationEnable: false, + holidayDate: new Date(), + holidayDateEnable: false, + holidayDateMessage: '', + checkboxSundayValue: false, + checkboxSaturdayValue: false, + weekendMessage: '', + enableWeekendMessage: false } const [config, setConfig] = useState(initialState) @@ -87,14 +95,35 @@ const ConfigModal = ({ open, onClose, change }) => { try { const { data } = await api.get('/settings') + console.log('data.config: ', data.config) + + const outBusinessHours = data.config.find((c) => c.key == "outBusinessHours") + const ticketExpiration = data.config.find((c) => c.key == "ticketExpiration") + const saturday = data.config.find((c) => c.key == "saturday") + const sunday = data.config.find((c) => c.key == "sunday") + const weekend = data.config.find((c) => c.key == "weekend") + + + const holiday = data.config.find((c) => c.key == "holiday") + setConfig({ - startTimeBus: data.outBusinessHours.startTime, - endTimeBus: data.outBusinessHours.endTime, - messageBus: data.outBusinessHours.message, - businessTimeEnalbe: data.outBusinessHours.value === 'enabled' ? true : false, - ticketTimeExpiration: data.ticketExpiration.startTime, - ticketExpirationMsg: data.ticketExpiration.message, - ticketExpirationEnable: data.ticketExpiration.value === 'enabled' ? true : false + startTimeBus: outBusinessHours.startTime, + endTimeBus: outBusinessHours.endTime, + messageBus: outBusinessHours.message, + businessTimeEnable: outBusinessHours.value === 'enabled' ? true : false, + + ticketTimeExpiration: ticketExpiration.startTime, + ticketExpirationMsg: ticketExpiration.message, + ticketExpirationEnable: ticketExpiration.value === 'enabled' ? true : false, + + checkboxSaturdayValue: saturday.value === 'enabled' ? true : false, + checkboxSundayValue: sunday.value === 'enabled' ? true : false, + weekendMessage: weekend.message, + enableWeekendMessage: weekend.value === 'enabled' ? true : false, + + holidayDate: holiday.startTime, + holidayDateMessage: holiday.message, + holidayDateEnable: holiday.value === 'enabled' ? true : false, }) } catch (err) { @@ -111,19 +140,35 @@ const ConfigModal = ({ open, onClose, change }) => { startTime: values.startTimeBus, endTime: values.endTimeBus, message: values.messageBus, - value: values.businessTimeEnalbe ? 'enabled' : 'disabled' + value: values.businessTimeEnable ? 'enabled' : 'disabled' }, ticketExpiration: { startTime: values.ticketTimeExpiration, message: values.ticketExpirationMsg, value: values.ticketExpirationEnable ? 'enabled' : 'disabled' + }, + weekend: { + message: values.weekendMessage, + value: values.enableWeekendMessage ? 'enabled' : 'disabled' + }, + saturday:{ + value: values.checkboxSaturdayValue ? 'enabled' : 'disabled' + }, + sunday: { + value: values.checkboxSundayValue ? 'enabled' : 'disabled' + }, + holiday: { + startTime: values.holidayDate, + message: values.holidayDateMessage, + value: values.holidayDateEnable ? 'enabled' : 'disabled' } + } - try { - - await api.put(`/settings/ticket`, values) + try { + + await api.put(`/settings/ticket`, values) toast.success('Atualização realizada com sucesso!') handleClose() @@ -157,10 +202,10 @@ const ConfigModal = ({ open, onClose, change }) => { enableReinitialize={true} // validationSchema={SessionSchema} onSubmit={(values, actions) => { - - setTimeout(() => { - handleSaveConfig(values) - actions.setSubmitting(false) + + setTimeout(() => { + handleSaveConfig(values) + actions.setSubmitting(false) }, 100) }} > @@ -196,8 +241,8 @@ const ConfigModal = ({ open, onClose, change }) => { } label={'Ativar/Desativar'} /> @@ -223,8 +268,108 @@ const ConfigModal = ({ open, onClose, change }) => { /> +
-
+ + + {/* Saturday and Sunday date */} +
+
+ + + +
+ + + } + label={'Ativar/Desativar'} + /> +
+
+ +
+ +
+ + {/* Holiday date */} +
+ + + + + } + label={'Ativar/Desativar'} + /> +
+
+ +
+ + + + + + +
+
{ openTo="hours" views={['hours', 'minutes',]} format="HH:mm" - /> + /> { ) } + + +const TimePickerField = ({ field, form, ...other }) => { + const { name, value } = field + + const handleChange = (time) => { + form.setFieldValue(name, time, true) + } + + return ( + + ) +} + + export default React.memo(ConfigModal)