umwd-components 0.1.69 → 0.1.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,11 +10,16 @@
10
10
  Object.defineProperty(exports, '__esModule', { value: true });
11
11
 
12
12
  var React = require('react');
13
- require('prop-types');
14
13
  var material = require('@mui/material');
15
14
  var isEmail = require('validator/lib/isEmail');
16
15
 
17
16
  function ContactForm(_ref) {
17
+ let {
18
+ data
19
+ } = _ref;
20
+ const {
21
+ maxWidth = "lg"
22
+ } = data;
18
23
  const [formValues, setFormValues] = React.useState({
19
24
  name: "",
20
25
  email: "",
@@ -23,14 +28,24 @@ function ContactForm(_ref) {
23
28
  });
24
29
  const [formErrors, setFormErrors] = React.useState({});
25
30
  const handleBlur = e => {
26
- console.log(e.target.id);
27
- console.log(e.target.value);
31
+ const {
32
+ id
33
+ } = e.target;
28
34
  const errors = validate(formValues);
29
- console.log(errors);
30
- setFormErrors({
31
- ...formErrors,
32
- [e.target.id]: errors[e.target.id]
33
- });
35
+ if (errors[id]) {
36
+ setFormErrors(prevErrors => ({
37
+ ...prevErrors,
38
+ [id]: errors[id]
39
+ }));
40
+ } else {
41
+ setFormErrors(prevErrors => {
42
+ const updatedErrors = {
43
+ ...prevErrors
44
+ };
45
+ delete updatedErrors[id];
46
+ return updatedErrors;
47
+ });
48
+ }
34
49
  };
35
50
  const handleChange = e => {
36
51
  const {
@@ -41,10 +56,14 @@ function ContactForm(_ref) {
41
56
  ...formValues,
42
57
  [id]: value
43
58
  });
44
- console.log("formValues", formValues);
45
59
  };
46
60
  const handleClear = () => {
47
- setFormValues({});
61
+ setFormValues({
62
+ name: "",
63
+ email: "",
64
+ subject: "",
65
+ message: ""
66
+ });
48
67
  };
49
68
  const handleSendCallback = () => {
50
69
  console.log("Send callback");
@@ -69,7 +88,16 @@ function ContactForm(_ref) {
69
88
  console.log("errors from validate", errors);
70
89
  return errors;
71
90
  };
72
- return /*#__PURE__*/React.createElement(material.Stack, {
91
+ return /*#__PURE__*/React.createElement(material.Container, {
92
+ maxWidth: maxWidth || "lg",
93
+ sx: {
94
+ my: 1
95
+ }
96
+ }, /*#__PURE__*/React.createElement(material.Paper, {
97
+ sx: {
98
+ p: 2
99
+ }
100
+ }, /*#__PURE__*/React.createElement(material.Stack, {
73
101
  spacing: 2
74
102
  }, /*#__PURE__*/React.createElement(material.Typography, {
75
103
  variant: "h6",
@@ -82,8 +110,8 @@ function ContactForm(_ref) {
82
110
  label: "Name",
83
111
  value: formValues.name,
84
112
  variant: "outlined",
85
- onBlur: e => handleBlur(e),
86
- onChange: e => handleChange(e),
113
+ onBlur: handleBlur,
114
+ onChange: handleChange,
87
115
  error: formErrors.name != undefined ? true : false,
88
116
  helperText: formErrors.name
89
117
  }), /*#__PURE__*/React.createElement(material.TextField, {
@@ -122,13 +150,12 @@ function ContactForm(_ref) {
122
150
  }, /*#__PURE__*/React.createElement(material.Button, {
123
151
  variant: "outlined",
124
152
  color: "primary",
125
- onClick: () => handleClear
153
+ onClick: handleClear
126
154
  }, "Clear"), /*#__PURE__*/React.createElement(material.Button, {
127
155
  variant: "contained",
128
156
  color: "primary",
129
157
  onClick: handleSendCallback
130
- }, "Send")));
158
+ }, "Send")))));
131
159
  }
132
- ContactForm.propTypes = {};
133
160
 
134
161
  exports.default = ContactForm;
@@ -16,6 +16,7 @@ var HeroSection = require('./HeroSection.js');
16
16
  var FeaturesSection = require('./FeaturesSection.js');
17
17
  var IconSection = require('./IconSection.js');
18
18
  var material = require('@mui/material');
19
+ var ContactForm = require('./ContactForm.js');
19
20
 
20
21
  function blockRenderer(block) {
21
22
  switch (block.__component) {
@@ -29,6 +30,11 @@ function blockRenderer(block) {
29
30
  key: block.id,
30
31
  data: block
31
32
  });
33
+ case "layout.contact-section":
34
+ return /*#__PURE__*/React.createElement(ContactForm.default, {
35
+ key: block.id,
36
+ data: block
37
+ });
32
38
  case "layout.text-image-section":
33
39
  return /*#__PURE__*/React.createElement(TextImageSection.default, {
34
40
  key: block.id,
@@ -23,7 +23,7 @@ function TextImageSection(_ref) {
23
23
  text,
24
24
  image,
25
25
  reverse = false,
26
- maxWidth
26
+ maxWidth = "lg"
27
27
  } = data;
28
28
 
29
29
  /* TODO Text_content should deal with linebreaks,
@@ -0,0 +1,77 @@
1
+ /*
2
+ * UMWD-Components
3
+ * @copyright Jelle Paulus
4
+ * @license MIT
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ Object.defineProperty(exports, '__esModule', { value: true });
10
+
11
+ var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
12
+ var React = require('react');
13
+ var material = require('@mui/material');
14
+
15
+ function WhatsAppClickToChatButton(_ref) {
16
+ let {
17
+ data
18
+ } = _ref;
19
+ const {
20
+ phoneNumber,
21
+ text,
22
+ message,
23
+ color,
24
+ round,
25
+ sx
26
+ } = data;
27
+ const theme = material.useTheme();
28
+ const formattedPhoneNumber = phoneNumber.replace(/\D/g, "");
29
+ const handleClick = () => {
30
+ let url = "https://wa.me/".concat(formattedPhoneNumber);
31
+ if (message) {
32
+ const formattedMessage = encodeURIComponent(message);
33
+ url = "https://wa.me/".concat(formattedPhoneNumber, "?text=").concat(formattedMessage);
34
+ }
35
+ window.open(url, "_blank");
36
+ };
37
+ return /*#__PURE__*/React.createElement(material.Button, {
38
+ variant: "contained",
39
+ onClick: handleClick,
40
+ startIcon: /*#__PURE__*/React.createElement(material.SvgIcon, {
41
+ sx: [round === true && {
42
+ m: 0,
43
+ p: 0
44
+ }]
45
+ }, /*#__PURE__*/React.createElement(WhatsAppIcon, {
46
+ fill: color || theme.palette.primary.contrastText
47
+ })),
48
+ sx: [{
49
+ ...sx
50
+ }, round === true && {
51
+ display: "grid",
52
+ justifyContent: "center",
53
+ alignItems: "center",
54
+ borderRadius: "50%",
55
+ p: 1,
56
+ minWidth: "unset",
57
+ ".MuiButton-startIcon": {
58
+ m: 0,
59
+ p: 0
60
+ }
61
+ }]
62
+ }, !round && (text || "Click to WhatsApp"));
63
+ }
64
+ function WhatsAppIcon(props) {
65
+ return /*#__PURE__*/React.createElement("svg", _rollupPluginBabelHelpers.extends({
66
+ viewBox: "0 0 30.667 30.667"
67
+ }, props), /*#__PURE__*/React.createElement("g", {
68
+ "stroke-width": "0"
69
+ }), /*#__PURE__*/React.createElement("g", {
70
+ "stroke-linecap": "round",
71
+ "stroke-linejoin": "round"
72
+ }), /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("path", {
73
+ d: "M30.667,14.939c0,8.25-6.74,14.938-15.056,14.938c-2.639,0-5.118-0.675-7.276-1.857L0,30.667l2.717-8.017 c-1.37-2.25-2.159-4.892-2.159-7.712C0.559,6.688,7.297,0,15.613,0C23.928,0.002,30.667,6.689,30.667,14.939z M15.61,2.382 c-6.979,0-12.656,5.634-12.656,12.56c0,2.748,0.896,5.292,2.411,7.362l-1.58,4.663l4.862-1.545c2,1.312,4.393,2.076,6.963,2.076 c6.979,0,12.658-5.633,12.658-12.559C28.27,8.016,22.59,2.382,15.61,2.382z M23.214,18.38c-0.094-0.151-0.34-0.243-0.708-0.427 c-0.367-0.184-2.184-1.069-2.521-1.189c-0.34-0.123-0.586-0.185-0.832,0.182c-0.243,0.367-0.951,1.191-1.168,1.437 c-0.215,0.245-0.43,0.276-0.799,0.095c-0.369-0.186-1.559-0.57-2.969-1.817c-1.097-0.972-1.838-2.169-2.052-2.536 c-0.217-0.366-0.022-0.564,0.161-0.746c0.165-0.165,0.369-0.428,0.554-0.643c0.185-0.213,0.246-0.364,0.369-0.609 c0.121-0.245,0.06-0.458-0.031-0.643c-0.092-0.184-0.829-1.984-1.138-2.717c-0.307-0.732-0.614-0.611-0.83-0.611 c-0.215,0-0.461-0.03-0.707-0.03S9.897,8.215,9.56,8.582s-1.291,1.252-1.291,3.054c0,1.804,1.321,3.543,1.506,3.787 c0.186,0.243,2.554,4.062,6.305,5.528c3.753,1.465,3.753,0.976,4.429,0.914c0.678-0.062,2.184-0.885,2.49-1.739 C23.307,19.268,23.307,18.533,23.214,18.38z"
74
+ })));
75
+ }
76
+
77
+ exports.default = WhatsAppClickToChatButton;
package/dist/cjs/index.js CHANGED
@@ -15,6 +15,7 @@ var Footer = require('./components/Footer.js');
15
15
  var ContactForm = require('./components/ContactForm.js');
16
16
  var WebsitePlaceholder = require('./components/WebsitePlaceholder.js');
17
17
  var BulletList = require('./components/BulletList.js');
18
+ var WhatsAppClickToChatButton = require('./components/WhatsAppClickToChatButton.js');
18
19
 
19
20
 
20
21
 
@@ -27,3 +28,4 @@ exports.Footer = Footer.default;
27
28
  exports.ContactForm = ContactForm.default;
28
29
  exports.WebsitePlaceholder = WebsitePlaceholder.default;
29
30
  exports.BulletList = BulletList.default;
31
+ exports.WhatsAppClickToChatButton = WhatsAppClickToChatButton.default;
@@ -6,11 +6,16 @@
6
6
  */
7
7
 
8
8
  import React from 'react';
9
- import 'prop-types';
10
- import { Stack, Typography, TextField, Button } from '@mui/material';
9
+ import { Container, Paper, Stack, Typography, TextField, Button } from '@mui/material';
11
10
  import isEmail from 'validator/lib/isEmail';
12
11
 
13
12
  function ContactForm(_ref) {
13
+ let {
14
+ data
15
+ } = _ref;
16
+ const {
17
+ maxWidth = "lg"
18
+ } = data;
14
19
  const [formValues, setFormValues] = React.useState({
15
20
  name: "",
16
21
  email: "",
@@ -19,14 +24,24 @@ function ContactForm(_ref) {
19
24
  });
20
25
  const [formErrors, setFormErrors] = React.useState({});
21
26
  const handleBlur = e => {
22
- console.log(e.target.id);
23
- console.log(e.target.value);
27
+ const {
28
+ id
29
+ } = e.target;
24
30
  const errors = validate(formValues);
25
- console.log(errors);
26
- setFormErrors({
27
- ...formErrors,
28
- [e.target.id]: errors[e.target.id]
29
- });
31
+ if (errors[id]) {
32
+ setFormErrors(prevErrors => ({
33
+ ...prevErrors,
34
+ [id]: errors[id]
35
+ }));
36
+ } else {
37
+ setFormErrors(prevErrors => {
38
+ const updatedErrors = {
39
+ ...prevErrors
40
+ };
41
+ delete updatedErrors[id];
42
+ return updatedErrors;
43
+ });
44
+ }
30
45
  };
31
46
  const handleChange = e => {
32
47
  const {
@@ -37,10 +52,14 @@ function ContactForm(_ref) {
37
52
  ...formValues,
38
53
  [id]: value
39
54
  });
40
- console.log("formValues", formValues);
41
55
  };
42
56
  const handleClear = () => {
43
- setFormValues({});
57
+ setFormValues({
58
+ name: "",
59
+ email: "",
60
+ subject: "",
61
+ message: ""
62
+ });
44
63
  };
45
64
  const handleSendCallback = () => {
46
65
  console.log("Send callback");
@@ -65,7 +84,16 @@ function ContactForm(_ref) {
65
84
  console.log("errors from validate", errors);
66
85
  return errors;
67
86
  };
68
- return /*#__PURE__*/React.createElement(Stack, {
87
+ return /*#__PURE__*/React.createElement(Container, {
88
+ maxWidth: maxWidth || "lg",
89
+ sx: {
90
+ my: 1
91
+ }
92
+ }, /*#__PURE__*/React.createElement(Paper, {
93
+ sx: {
94
+ p: 2
95
+ }
96
+ }, /*#__PURE__*/React.createElement(Stack, {
69
97
  spacing: 2
70
98
  }, /*#__PURE__*/React.createElement(Typography, {
71
99
  variant: "h6",
@@ -78,8 +106,8 @@ function ContactForm(_ref) {
78
106
  label: "Name",
79
107
  value: formValues.name,
80
108
  variant: "outlined",
81
- onBlur: e => handleBlur(e),
82
- onChange: e => handleChange(e),
109
+ onBlur: handleBlur,
110
+ onChange: handleChange,
83
111
  error: formErrors.name != undefined ? true : false,
84
112
  helperText: formErrors.name
85
113
  }), /*#__PURE__*/React.createElement(TextField, {
@@ -118,13 +146,12 @@ function ContactForm(_ref) {
118
146
  }, /*#__PURE__*/React.createElement(Button, {
119
147
  variant: "outlined",
120
148
  color: "primary",
121
- onClick: () => handleClear
149
+ onClick: handleClear
122
150
  }, "Clear"), /*#__PURE__*/React.createElement(Button, {
123
151
  variant: "contained",
124
152
  color: "primary",
125
153
  onClick: handleSendCallback
126
- }, "Send")));
154
+ }, "Send")))));
127
155
  }
128
- ContactForm.propTypes = {};
129
156
 
130
157
  export { ContactForm as default };
@@ -12,6 +12,7 @@ import { HeroSection } from './HeroSection.js';
12
12
  import { FeatureSection } from './FeaturesSection.js';
13
13
  import { IconSection } from './IconSection.js';
14
14
  import { Box } from '@mui/material';
15
+ import ContactForm from './ContactForm.js';
15
16
 
16
17
  function blockRenderer(block) {
17
18
  switch (block.__component) {
@@ -25,6 +26,11 @@ function blockRenderer(block) {
25
26
  key: block.id,
26
27
  data: block
27
28
  });
29
+ case "layout.contact-section":
30
+ return /*#__PURE__*/React.createElement(ContactForm, {
31
+ key: block.id,
32
+ data: block
33
+ });
28
34
  case "layout.text-image-section":
29
35
  return /*#__PURE__*/React.createElement(TextImageSection, {
30
36
  key: block.id,
@@ -19,7 +19,7 @@ function TextImageSection(_ref) {
19
19
  text,
20
20
  image,
21
21
  reverse = false,
22
- maxWidth
22
+ maxWidth = "lg"
23
23
  } = data;
24
24
 
25
25
  /* TODO Text_content should deal with linebreaks,
@@ -0,0 +1,73 @@
1
+ /*
2
+ * UMWD-Components
3
+ * @copyright Jelle Paulus
4
+ * @license MIT
5
+ */
6
+
7
+ import { extends as _extends } from '../_virtual/_rollupPluginBabelHelpers.js';
8
+ import React from 'react';
9
+ import { useTheme, Button, SvgIcon } from '@mui/material';
10
+
11
+ function WhatsAppClickToChatButton(_ref) {
12
+ let {
13
+ data
14
+ } = _ref;
15
+ const {
16
+ phoneNumber,
17
+ text,
18
+ message,
19
+ color,
20
+ round,
21
+ sx
22
+ } = data;
23
+ const theme = useTheme();
24
+ const formattedPhoneNumber = phoneNumber.replace(/\D/g, "");
25
+ const handleClick = () => {
26
+ let url = "https://wa.me/".concat(formattedPhoneNumber);
27
+ if (message) {
28
+ const formattedMessage = encodeURIComponent(message);
29
+ url = "https://wa.me/".concat(formattedPhoneNumber, "?text=").concat(formattedMessage);
30
+ }
31
+ window.open(url, "_blank");
32
+ };
33
+ return /*#__PURE__*/React.createElement(Button, {
34
+ variant: "contained",
35
+ onClick: handleClick,
36
+ startIcon: /*#__PURE__*/React.createElement(SvgIcon, {
37
+ sx: [round === true && {
38
+ m: 0,
39
+ p: 0
40
+ }]
41
+ }, /*#__PURE__*/React.createElement(WhatsAppIcon, {
42
+ fill: color || theme.palette.primary.contrastText
43
+ })),
44
+ sx: [{
45
+ ...sx
46
+ }, round === true && {
47
+ display: "grid",
48
+ justifyContent: "center",
49
+ alignItems: "center",
50
+ borderRadius: "50%",
51
+ p: 1,
52
+ minWidth: "unset",
53
+ ".MuiButton-startIcon": {
54
+ m: 0,
55
+ p: 0
56
+ }
57
+ }]
58
+ }, !round && (text || "Click to WhatsApp"));
59
+ }
60
+ function WhatsAppIcon(props) {
61
+ return /*#__PURE__*/React.createElement("svg", _extends({
62
+ viewBox: "0 0 30.667 30.667"
63
+ }, props), /*#__PURE__*/React.createElement("g", {
64
+ "stroke-width": "0"
65
+ }), /*#__PURE__*/React.createElement("g", {
66
+ "stroke-linecap": "round",
67
+ "stroke-linejoin": "round"
68
+ }), /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("path", {
69
+ d: "M30.667,14.939c0,8.25-6.74,14.938-15.056,14.938c-2.639,0-5.118-0.675-7.276-1.857L0,30.667l2.717-8.017 c-1.37-2.25-2.159-4.892-2.159-7.712C0.559,6.688,7.297,0,15.613,0C23.928,0.002,30.667,6.689,30.667,14.939z M15.61,2.382 c-6.979,0-12.656,5.634-12.656,12.56c0,2.748,0.896,5.292,2.411,7.362l-1.58,4.663l4.862-1.545c2,1.312,4.393,2.076,6.963,2.076 c6.979,0,12.658-5.633,12.658-12.559C28.27,8.016,22.59,2.382,15.61,2.382z M23.214,18.38c-0.094-0.151-0.34-0.243-0.708-0.427 c-0.367-0.184-2.184-1.069-2.521-1.189c-0.34-0.123-0.586-0.185-0.832,0.182c-0.243,0.367-0.951,1.191-1.168,1.437 c-0.215,0.245-0.43,0.276-0.799,0.095c-0.369-0.186-1.559-0.57-2.969-1.817c-1.097-0.972-1.838-2.169-2.052-2.536 c-0.217-0.366-0.022-0.564,0.161-0.746c0.165-0.165,0.369-0.428,0.554-0.643c0.185-0.213,0.246-0.364,0.369-0.609 c0.121-0.245,0.06-0.458-0.031-0.643c-0.092-0.184-0.829-1.984-1.138-2.717c-0.307-0.732-0.614-0.611-0.83-0.611 c-0.215,0-0.461-0.03-0.707-0.03S9.897,8.215,9.56,8.582s-1.291,1.252-1.291,3.054c0,1.804,1.321,3.543,1.506,3.787 c0.186,0.243,2.554,4.062,6.305,5.528c3.753,1.465,3.753,0.976,4.429,0.914c0.678-0.062,2.184-0.885,2.49-1.739 C23.307,19.268,23.307,18.533,23.214,18.38z"
70
+ })));
71
+ }
72
+
73
+ export { WhatsAppClickToChatButton as default };
package/dist/esm/index.js CHANGED
@@ -13,3 +13,4 @@ export { default as Footer } from './components/Footer.js';
13
13
  export { default as ContactForm } from './components/ContactForm.js';
14
14
  export { default as WebsitePlaceholder } from './components/WebsitePlaceholder.js';
15
15
  export { default as BulletList } from './components/BulletList.js';
16
+ export { default as WhatsAppClickToChatButton } from './components/WhatsAppClickToChatButton.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umwd-components",
3
- "version": "0.1.69",
3
+ "version": "0.1.71",
4
4
  "description": "UMWD Component library",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -88,6 +88,7 @@
88
88
  "@fontsource/roboto": "^5.0.12",
89
89
  "@mui/types": "^7.2.14",
90
90
  "@rollup/plugin-commonjs": "^25.0.7",
91
+ "@types/validator": "^13.11.9",
91
92
  "next-router-mock": "^0.9.12",
92
93
  "react": "^18.2.0",
93
94
  "react-dnd": "^16.0.1",
@@ -0,0 +1,179 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import {
5
+ Container,
6
+ Paper,
7
+ TextField,
8
+ Typography,
9
+ Stack,
10
+ Button,
11
+ } from "@mui/material";
12
+ import isEmail from "validator/lib/isEmail";
13
+ import { Breakpoint } from "@mui/system";
14
+
15
+ interface ContactFormProps {
16
+ id: number;
17
+ __component: string;
18
+ title: string;
19
+ maxWidth: Breakpoint;
20
+ }
21
+
22
+ function ContactForm({ data }: { readonly data: ContactFormProps }) {
23
+ const { maxWidth = "lg" } = data;
24
+
25
+ type FormValues = {
26
+ name: string;
27
+ email: string;
28
+ subject: string;
29
+ message: string;
30
+ };
31
+
32
+ const [formValues, setFormValues] = React.useState<FormValues>({
33
+ name: "",
34
+ email: "",
35
+ subject: "",
36
+ message: "",
37
+ });
38
+
39
+ type FormErrors = {
40
+ name?: string;
41
+ email?: string;
42
+ subject?: string;
43
+ message?: string;
44
+ [key: string]: string | undefined; // Add index signature
45
+ };
46
+
47
+ const [formErrors, setFormErrors] = React.useState<FormErrors>({});
48
+
49
+ const handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
50
+ const { id } = e.target;
51
+ const errors = validate(formValues);
52
+ if (errors[id]) {
53
+ setFormErrors((prevErrors) => ({
54
+ ...prevErrors,
55
+ [id]: errors[id],
56
+ }));
57
+ } else {
58
+ setFormErrors((prevErrors) => {
59
+ const updatedErrors = { ...prevErrors };
60
+ delete updatedErrors[id];
61
+ return updatedErrors;
62
+ });
63
+ }
64
+ };
65
+
66
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
67
+ const { id, value } = e.target;
68
+ setFormValues({ ...formValues, [id]: value });
69
+ };
70
+
71
+ const handleClear = () => {
72
+ setFormValues({
73
+ name: "",
74
+ email: "",
75
+ subject: "",
76
+ message: "",
77
+ });
78
+ };
79
+
80
+ const handleSendCallback = () => {
81
+ console.log("Send callback");
82
+ };
83
+
84
+ const validate = (values: FormValues) => {
85
+ console.log("values from validate", values);
86
+
87
+ let errors: Partial<FormErrors> = {};
88
+
89
+ if (values.name === "") {
90
+ errors.name = "Name is required";
91
+ }
92
+ if (values.email === "") {
93
+ errors.email = "Email is required";
94
+ } else if (!isEmail(values.email)) {
95
+ errors.email = "Invalid email";
96
+ }
97
+ if (values.subject === "") {
98
+ errors.subject = "Subject is required";
99
+ }
100
+ if (values.message === "") {
101
+ errors.message = "Message is required";
102
+ }
103
+
104
+ console.log("errors from validate", errors);
105
+
106
+ return errors;
107
+ };
108
+
109
+ return (
110
+ <Container maxWidth={maxWidth || "lg"} sx={{ my: 1 }}>
111
+ <Paper sx={{ p: 2 }}>
112
+ <Stack spacing={2}>
113
+ <Typography variant="h6" align="center">
114
+ Write us
115
+ </Typography>
116
+ <Typography variant="body1" align="center">
117
+ We're open for any suggestion or just to have a chat
118
+ </Typography>
119
+ <TextField
120
+ id="name"
121
+ label="Name"
122
+ value={formValues.name}
123
+ variant="outlined"
124
+ onBlur={handleBlur}
125
+ onChange={handleChange}
126
+ error={formErrors.name != undefined ? true : false}
127
+ helperText={formErrors.name}
128
+ />
129
+ <TextField
130
+ id="email"
131
+ label="Email"
132
+ value={formValues.email}
133
+ variant="outlined"
134
+ onBlur={handleBlur}
135
+ onChange={handleChange}
136
+ error={formErrors.email != undefined ? true : false}
137
+ helperText={formErrors.email}
138
+ />
139
+ <TextField
140
+ id="subject"
141
+ label="Subject"
142
+ value={formValues.subject}
143
+ variant="outlined"
144
+ onBlur={handleBlur}
145
+ onChange={handleChange}
146
+ error={formErrors.subject != undefined}
147
+ helperText={formErrors.subject}
148
+ />
149
+ <TextField
150
+ id="message"
151
+ label="Message"
152
+ value={formValues.message}
153
+ variant="outlined"
154
+ multiline
155
+ minRows={5}
156
+ onBlur={handleBlur}
157
+ onChange={handleChange}
158
+ error={formErrors.message != undefined}
159
+ helperText={formErrors.message}
160
+ />
161
+ <Stack direction={"row"} spacing={2} justifyContent={"end"}>
162
+ <Button variant="outlined" color="primary" onClick={handleClear}>
163
+ Clear
164
+ </Button>
165
+ <Button
166
+ variant="contained"
167
+ color="primary"
168
+ onClick={handleSendCallback}
169
+ >
170
+ Send
171
+ </Button>
172
+ </Stack>
173
+ </Stack>
174
+ </Paper>
175
+ </Container>
176
+ );
177
+ }
178
+
179
+ export default ContactForm;
@@ -7,6 +7,7 @@ import { HeroSection } from "./HeroSection.tsx";
7
7
  import { FeatureSection } from "./FeaturesSection.tsx";
8
8
  import { IconSection } from "./IconSection.tsx";
9
9
  import { Box } from "@mui/material";
10
+ import ContactForm from "./ContactForm.tsx";
10
11
 
11
12
  function blockRenderer(block) {
12
13
  switch (block.__component) {
@@ -14,10 +15,13 @@ function blockRenderer(block) {
14
15
  return <HeroSection key={block.id} data={block} />;
15
16
  case "layout.features-section":
16
17
  return <FeatureSection key={block.id} data={block} />;
18
+ case "layout.contact-section":
19
+ return <ContactForm key={block.id} data={block} />;
17
20
  case "layout.text-image-section":
18
21
  return <TextImageSection key={block.id} data={block} />;
19
22
  case "layout.icon-section":
20
23
  return <IconSection key={block.id} data={block} />;
24
+
21
25
  default:
22
26
  return null;
23
27
  }
@@ -24,7 +24,7 @@ interface TextImageSectionProps {
24
24
  }
25
25
 
26
26
  function TextImageSection({ data }: Readonly<TextImageSectionProps>) {
27
- const { title, text, image, reverse = false, maxWidth } = data;
27
+ const { title, text, image, reverse = false, maxWidth = "lg" } = data;
28
28
 
29
29
  /* TODO Text_content should deal with linebreaks,
30
30
  reading up upon mui-markdown docs is advised */
@@ -0,0 +1,72 @@
1
+ import React from "react";
2
+ import { Button, SvgIcon, useTheme } from "@mui/material";
3
+
4
+ interface WhatsAppClickToChatButtonProps {
5
+ phoneNumber: string;
6
+ text?: string;
7
+ message?: string;
8
+ color?: string;
9
+ round?: boolean;
10
+ sx?: React.CSSProperties;
11
+ }
12
+
13
+ function WhatsAppClickToChatButton({
14
+ data,
15
+ }: {
16
+ readonly data: WhatsAppClickToChatButtonProps;
17
+ }) {
18
+ const { phoneNumber, text, message, color, round, sx } = data;
19
+
20
+ const theme = useTheme();
21
+
22
+ const formattedPhoneNumber = phoneNumber.replace(/\D/g, "");
23
+
24
+ const handleClick = () => {
25
+ let url = `https://wa.me/${formattedPhoneNumber}`;
26
+ if (message) {
27
+ const formattedMessage = encodeURIComponent(message);
28
+ url = `https://wa.me/${formattedPhoneNumber}?text=${formattedMessage}`;
29
+ }
30
+ window.open(url, "_blank");
31
+ };
32
+
33
+ return (
34
+ <Button
35
+ variant="contained"
36
+ onClick={handleClick}
37
+ startIcon={
38
+ <SvgIcon sx={[round === true && { m: 0, p: 0 }]}>
39
+ <WhatsAppIcon fill={color || theme.palette.primary.contrastText} />
40
+ </SvgIcon>
41
+ }
42
+ sx={[
43
+ { ...sx },
44
+ round === true && {
45
+ display: "grid",
46
+ justifyContent: "center",
47
+ alignItems: "center",
48
+ borderRadius: "50%",
49
+ p: 1,
50
+ minWidth: "unset",
51
+ ".MuiButton-startIcon": { m: 0, p: 0 },
52
+ },
53
+ ]}
54
+ >
55
+ {!round && (text || "Click to WhatsApp")}
56
+ </Button>
57
+ );
58
+ }
59
+
60
+ export default WhatsAppClickToChatButton;
61
+
62
+ function WhatsAppIcon(props: any) {
63
+ return (
64
+ <svg viewBox="0 0 30.667 30.667" {...props}>
65
+ <g stroke-width="0"></g>
66
+ <g stroke-linecap="round" stroke-linejoin="round"></g>
67
+ <g>
68
+ <path d="M30.667,14.939c0,8.25-6.74,14.938-15.056,14.938c-2.639,0-5.118-0.675-7.276-1.857L0,30.667l2.717-8.017 c-1.37-2.25-2.159-4.892-2.159-7.712C0.559,6.688,7.297,0,15.613,0C23.928,0.002,30.667,6.689,30.667,14.939z M15.61,2.382 c-6.979,0-12.656,5.634-12.656,12.56c0,2.748,0.896,5.292,2.411,7.362l-1.58,4.663l4.862-1.545c2,1.312,4.393,2.076,6.963,2.076 c6.979,0,12.658-5.633,12.658-12.559C28.27,8.016,22.59,2.382,15.61,2.382z M23.214,18.38c-0.094-0.151-0.34-0.243-0.708-0.427 c-0.367-0.184-2.184-1.069-2.521-1.189c-0.34-0.123-0.586-0.185-0.832,0.182c-0.243,0.367-0.951,1.191-1.168,1.437 c-0.215,0.245-0.43,0.276-0.799,0.095c-0.369-0.186-1.559-0.57-2.969-1.817c-1.097-0.972-1.838-2.169-2.052-2.536 c-0.217-0.366-0.022-0.564,0.161-0.746c0.165-0.165,0.369-0.428,0.554-0.643c0.185-0.213,0.246-0.364,0.369-0.609 c0.121-0.245,0.06-0.458-0.031-0.643c-0.092-0.184-0.829-1.984-1.138-2.717c-0.307-0.732-0.614-0.611-0.83-0.611 c-0.215,0-0.461-0.03-0.707-0.03S9.897,8.215,9.56,8.582s-1.291,1.252-1.291,3.054c0,1.804,1.321,3.543,1.506,3.787 c0.186,0.243,2.554,4.062,6.305,5.528c3.753,1.465,3.753,0.976,4.429,0.914c0.678-0.062,2.184-0.885,2.49-1.739 C23.307,19.268,23.307,18.533,23.214,18.38z"></path>
69
+ </g>
70
+ </svg>
71
+ );
72
+ }
package/src/index.js CHANGED
@@ -10,6 +10,7 @@ export { default as NavBar } from "./components/NavBar";
10
10
  export { default as TextImageSection } from "./components/TextImageSection.tsx";
11
11
  export { default as Page } from "./components/Page";
12
12
  export { default as Footer } from "./components/Footer";
13
- export { default as ContactForm } from "./components/ContactForm";
13
+ export { default as ContactForm } from "./components/ContactForm.tsx";
14
14
  export { default as WebsitePlaceholder } from "./components/WebsitePlaceholder";
15
15
  export { default as BulletList } from "./components/BulletList";
16
+ export { default as WhatsAppClickToChatButton } from "./components/WhatsAppClickToChatButton.tsx";
@@ -313,5 +313,10 @@ AMH.args = {
313
313
  },
314
314
  ],
315
315
  },
316
+ {
317
+ id: 1,
318
+ __component: "layout.contact-section",
319
+ title: "Contact us",
320
+ },
316
321
  ],
317
322
  };
@@ -0,0 +1,69 @@
1
+ import React from "react";
2
+ import WhatsAppClickToChatButton from "../components/WhatsAppClickToChatButton.tsx";
3
+
4
+ export default {
5
+ title: "UMWD/WhatsAppClickToChatButton",
6
+ component: WhatsAppClickToChatButton,
7
+ };
8
+
9
+ const Template = ({ ...args }) => {
10
+ return <WhatsAppClickToChatButton {...args} />;
11
+ };
12
+
13
+ export const Round = Template.bind({});
14
+
15
+ Round.args = {
16
+ data: {
17
+ phoneNumber: "+1234567890",
18
+ message: "Hello, how can I help you?",
19
+ color: "#25D366",
20
+ round: true,
21
+ sx: {
22
+ position: "fixed",
23
+ bottom: "20px",
24
+ right: "20px",
25
+ zIndex: 1000,
26
+ width: "40px",
27
+ height: "40px",
28
+ },
29
+ },
30
+ };
31
+
32
+ export const WithText = Template.bind({});
33
+
34
+ WithText.args = {
35
+ data: {
36
+ phoneNumber: "+1234567890",
37
+ message: "Hello, how can I help you?",
38
+ color: "red",
39
+ round: false,
40
+ sx: {
41
+ position: "fixed",
42
+ bottom: "20px",
43
+ right: "20px",
44
+ },
45
+ },
46
+ };
47
+
48
+ export const SX = Template.bind({});
49
+
50
+ SX.args = {
51
+ data: {
52
+ phoneNumber: "+1234567890",
53
+ message: "Hello, how can I help you?",
54
+ color: "red",
55
+ round: true,
56
+ sx: {
57
+ position: "fixed",
58
+ bottom: "20px",
59
+ right: "20px",
60
+ zIndex: 1000,
61
+ width: "70px",
62
+ height: "70px",
63
+ ".MuiSvgIcon-root": {
64
+ width: "40px",
65
+ height: "40px",
66
+ },
67
+ },
68
+ },
69
+ };
@@ -1,131 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import PropTypes from "prop-types";
5
- import { TextField, Typography, Stack, Button } from "@mui/material";
6
- import isEmail from "validator/lib/isEmail";
7
-
8
- function ContactForm({ ...args }) {
9
- const [formValues, setFormValues] = React.useState({
10
- name: "",
11
- email: "",
12
- subject: "",
13
- message: "",
14
- });
15
- const [formErrors, setFormErrors] = React.useState({});
16
-
17
- const handleBlur = (e) => {
18
- console.log(e.target.id);
19
- console.log(e.target.value);
20
- const errors = validate(formValues);
21
- console.log(errors);
22
- setFormErrors({ ...formErrors, [e.target.id]: errors[e.target.id] });
23
- };
24
-
25
- const handleChange = (e) => {
26
- const { id, value } = e.target;
27
- setFormValues({ ...formValues, [id]: value });
28
- console.log("formValues", formValues);
29
- };
30
-
31
- const handleClear = () => {
32
- setFormValues({});
33
- };
34
-
35
- const handleSendCallback = () => {
36
- console.log("Send callback");
37
- };
38
-
39
- const validate = (values) => {
40
- console.log("values from validate", values);
41
- let errors = {};
42
-
43
- if (values.name === "") {
44
- errors.name = "Name is required";
45
- }
46
- if (values.email === "") {
47
- errors.email = "Email is required";
48
- } else if (!isEmail(values.email)) {
49
- errors.email = "Invalid email";
50
- }
51
- if (values.subject === "") {
52
- errors.subject = "Subject is required";
53
- }
54
- if (values.message === "") {
55
- errors.message = "Message is required";
56
- }
57
-
58
- console.log("errors from validate", errors);
59
-
60
- return errors;
61
- };
62
-
63
- return (
64
- <Stack spacing={2}>
65
- <Typography variant="h6" align="center">
66
- Write us
67
- </Typography>
68
- <Typography variant="body1" align="center">
69
- We're open for any suggestion or just to have a chat
70
- </Typography>
71
- <TextField
72
- id="name"
73
- label="Name"
74
- value={formValues.name}
75
- variant="outlined"
76
- onBlur={(e) => handleBlur(e)}
77
- onChange={(e) => handleChange(e)}
78
- error={formErrors.name != undefined ? true : false}
79
- helperText={formErrors.name}
80
- />
81
- <TextField
82
- id="email"
83
- label="Email"
84
- value={formValues.email}
85
- variant="outlined"
86
- onBlur={handleBlur}
87
- onChange={handleChange}
88
- error={formErrors.email != undefined ? true : false}
89
- helperText={formErrors.email}
90
- />
91
- <TextField
92
- id="subject"
93
- label="Subject"
94
- value={formValues.subject}
95
- variant="outlined"
96
- onBlur={handleBlur}
97
- onChange={handleChange}
98
- error={formErrors.subject != undefined}
99
- helperText={formErrors.subject}
100
- />
101
- <TextField
102
- id="message"
103
- label="Message"
104
- value={formValues.message}
105
- variant="outlined"
106
- multiline
107
- minRows={5}
108
- onBlur={handleBlur}
109
- onChange={handleChange}
110
- error={formErrors.message != undefined}
111
- helperText={formErrors.message}
112
- />
113
- <Stack direction={"row"} spacing={2} justifyContent={"end"}>
114
- <Button variant="outlined" color="primary" onClick={() => handleClear}>
115
- Clear
116
- </Button>
117
- <Button
118
- variant="contained"
119
- color="primary"
120
- onClick={handleSendCallback}
121
- >
122
- Send
123
- </Button>
124
- </Stack>
125
- </Stack>
126
- );
127
- }
128
-
129
- ContactForm.propTypes = {};
130
-
131
- export default ContactForm;