diff --git a/public/rich-components/calendar.svg b/public/rich-components/calendar.svg
new file mode 100644
index 00000000..3e652af2
--- /dev/null
+++ b/public/rich-components/calendar.svg
@@ -0,0 +1,68 @@
+
\ No newline at end of file
diff --git a/src/common/components/front-rich-components/calendar/calendar.business.tsx b/src/common/components/front-rich-components/calendar/calendar.business.tsx
new file mode 100644
index 00000000..c5883373
--- /dev/null
+++ b/src/common/components/front-rich-components/calendar/calendar.business.tsx
@@ -0,0 +1,28 @@
+// TODO: #250 Add Unit tests
+// https://github.com/Lemoncode/quickmock/issues/250
+
+export const calculatePreviousMonth = (date: Date) =>
+ new Date(date.getFullYear(), date.getMonth() - 1, 1);
+
+export const calculateNextMonth = (date: Date) =>
+ new Date(date.getFullYear(), date.getMonth() + 1, 1);
+
+export const getCurrentMonthDays = (date: Date) => {
+ const month = date.toLocaleString('en', { month: 'long' });
+ const year = date.getFullYear();
+ const daysInMonth = new Date(year, date.getMonth() + 1, 0).getDate();
+ const startDay = new Date(year, date.getMonth(), 1).getDay();
+
+ const days = [];
+ let week = new Array(startDay).fill(null); // Fill the first week with nulls up to the start day
+
+ for (let day = 1; day <= daysInMonth; day++) {
+ week.push(day);
+ if (week.length === 7 || day === daysInMonth) {
+ days.push(week);
+ week = [];
+ }
+ }
+
+ return { month, year, days };
+};
diff --git a/src/common/components/front-rich-components/calendar/calendar.tsx b/src/common/components/front-rich-components/calendar/calendar.tsx
new file mode 100644
index 00000000..5806a816
--- /dev/null
+++ b/src/common/components/front-rich-components/calendar/calendar.tsx
@@ -0,0 +1,166 @@
+import { useState, forwardRef } from 'react';
+import { Group, Rect, Text, Line } from 'react-konva';
+import { ShapeSizeRestrictions } from '@/core/model';
+import { ShapeProps } from '../../front-components/shape.model';
+import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions';
+import {
+ calculateNextMonth,
+ calculatePreviousMonth,
+ getCurrentMonthDays,
+} from './calendar.business';
+
+const calendarShapeSizeRestrictions: ShapeSizeRestrictions = {
+ minWidth: 350,
+ minHeight: 350,
+ maxWidth: -1,
+ maxHeight: -1,
+ defaultWidth: 500,
+ defaultHeight: 500,
+};
+
+export const getCalendarShapeSizeRestrictions = (): ShapeSizeRestrictions =>
+ calendarShapeSizeRestrictions;
+
+export const CalendarShape = forwardRef(
+ ({ x, y, width, height, id, onSelected, ...shapeProps }, ref) => {
+ const { width: restrictedWidth, height: restrictedHeight } =
+ fitSizeToShapeSizeRestrictions(
+ calendarShapeSizeRestrictions,
+ width,
+ height
+ );
+
+ const [currentDate, setCurrentDate] = useState(new Date());
+
+ const handlePrevMonth = () => {
+ setCurrentDate(prevDate => calculatePreviousMonth(prevDate));
+ };
+
+ const handleNextMonth = () => {
+ setCurrentDate(prevDate => calculateNextMonth(prevDate));
+ };
+
+ const { month, year, days } = getCurrentMonthDays(currentDate);
+
+ const margin = 10;
+ const headerHeight = 50;
+ const dayBoxWidth = (restrictedWidth - margin * 2) / 7;
+ const dayBoxHeight = (height - headerHeight) / days.length;
+
+ return (
+ onSelected(id, 'calendar')}
+ >
+ {/* Encabezado del calendario */}
+
+
+ {/* Left arrow */}
+
+
+ {/* Year and month */}
+
+
+
+ {/* Right arrow */}
+
+
+ {/* Calendar table */}
+
+
+ {/* Week days */}
+ {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, i) => (
+
+ ))}
+
+ {/* Month days */}
+ {days.map((week: any[], rowIndex: number) =>
+ week.map((day, colIndex) => (
+
+ ))
+ )}
+
+ );
+ }
+);
+
+export default CalendarShape;
diff --git a/src/common/components/front-rich-components/calendar/index.ts b/src/common/components/front-rich-components/calendar/index.ts
new file mode 100644
index 00000000..edaf8f07
--- /dev/null
+++ b/src/common/components/front-rich-components/calendar/index.ts
@@ -0,0 +1 @@
+export * from './calendar';
diff --git a/src/common/components/front-rich-components/index.ts b/src/common/components/front-rich-components/index.ts
index c1cc421f..078dd3eb 100644
--- a/src/common/components/front-rich-components/index.ts
+++ b/src/common/components/front-rich-components/index.ts
@@ -6,4 +6,5 @@ export * from './map-chart';
export * from './video-player';
export * from './bar-chart';
export * from './line-chart';
+export * from './calendar/calendar';
export * from './table/table';
diff --git a/src/core/model/index.ts b/src/core/model/index.ts
index 3471f279..f8e99746 100644
--- a/src/core/model/index.ts
+++ b/src/core/model/index.ts
@@ -47,7 +47,9 @@ export type ShapeType =
| 'largeArrow'
| 'bar'
| 'triangle'
+ | 'horizontalScrollBar'
| 'image'
+ | 'calendar'
| 'image'
| 'table'
| 'verticalScrollBar'
@@ -95,6 +97,7 @@ export const ShapeDisplayName: Record = {
image: 'Image',
table: 'Table',
horizontalScrollBar: 'Horizontal Scroll Bar',
+ calendar: 'Calendar',
verticalScrollBar: 'Vertical Scroll Bar',
};
diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts
index 128720c9..61842566 100644
--- a/src/pods/canvas/canvas.model.ts
+++ b/src/pods/canvas/canvas.model.ts
@@ -50,6 +50,7 @@ import {
getHorizontalMenuShapeSizeRestrictions,
getMapChartShapeSizeRestrictions,
getLineChartShapeSizeRestrictions,
+ getCalendarShapeSizeRestrictions,
getTableSizeRestrictions,
} from '@/common/components/front-rich-components';
import {
@@ -269,6 +270,11 @@ export const getDefaultSizeFromShape = (shapeType: ShapeType): Size => {
width: getHorizontalScrollBarShapeSizeRestrictions().defaultWidth,
height: getHorizontalScrollBarShapeSizeRestrictions().defaultHeight,
};
+ case 'calendar':
+ return {
+ width: getCalendarShapeSizeRestrictions().defaultWidth,
+ height: getCalendarShapeSizeRestrictions().defaultHeight,
+ };
case 'verticalScrollBar':
return {
width: getVerticalScrollBarShapeSizeRestrictions().defaultWidth,
diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx
index 97b13702..afde584f 100644
--- a/src/pods/canvas/shape-renderer/index.tsx
+++ b/src/pods/canvas/shape-renderer/index.tsx
@@ -53,6 +53,7 @@ import {
import { renderSmalltext } from './simple-text-components/smalltext.renderer';
import { renderParagraph } from './simple-text-components/paragraph.renderer';
import { renderImage } from './simple-basic-shapes/image.renderer';
+import { renderCalendar } from './simple-rich-components/calendar.renderer';
export const renderShapeComponent = (
shape: ShapeModel,
@@ -99,6 +100,8 @@ export const renderShapeComponent = (
return renderPieChart(shape, shapeRenderedProps);
case 'map':
return renderMapChart(shape, shapeRenderedProps);
+ case 'calendar':
+ return renderCalendar(shape, shapeRenderedProps);
case 'linechart':
return renderLineChart(shape, shapeRenderedProps);
case 'diamond':
diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/calendar.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/calendar.renderer.tsx
new file mode 100644
index 00000000..50b92ff4
--- /dev/null
+++ b/src/pods/canvas/shape-renderer/simple-rich-components/calendar.renderer.tsx
@@ -0,0 +1,30 @@
+import { CalendarShape } from '@/common/components/front-rich-components/calendar';
+import { ShapeRendererProps } from '../model';
+import { ShapeModel } from '@/core/model';
+
+export const renderCalendar = (
+ shape: ShapeModel,
+ shapeRenderedProps: ShapeRendererProps
+) => {
+ const { handleSelected, shapeRefs, handleDragEnd, handleTransform } =
+ shapeRenderedProps;
+
+ return (
+
+ );
+};
diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts
index cffb8531..423ba71e 100644
--- a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts
+++ b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts
@@ -6,4 +6,5 @@ export * from './map-chart.renderer';
export * from './breadcrumb.renderer';
export * from './bar-chart.renderer';
export * from './line-chart.renderer';
+export * from './calendar.renderer';
export * from './table.renderer';
diff --git a/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts b/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts
index 36dd071e..b6f96c2f 100644
--- a/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts
+++ b/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts
@@ -12,5 +12,6 @@ export const mockRichComponentsCollection: ItemInfo[] = [
{ thumbnailSrc: '/rich-components/map.svg', type: 'map' },
{ thumbnailSrc: '/rich-components/barchart.svg', type: 'bar' },
{ thumbnailSrc: '/rich-components/line-chart.svg', type: 'linechart' },
+ { thumbnailSrc: '/rich-components/calendar.svg', type: 'calendar' },
{ thumbnailSrc: '/rich-components/table.svg', type: 'table' },
];