form-craft-package 1.8.2-dev.0 → 1.8.2-dev.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-craft-package",
3
- "version": "1.8.2-dev.0",
3
+ "version": "1.8.2-dev.1",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -0,0 +1,40 @@
1
+ import { useState } from 'react'
2
+
3
+ export default function CompanyLogoSection({
4
+ location = LogoLocationEnum.Authenticated,
5
+ logoUrl,
6
+ isPreview,
7
+ }: {
8
+ location?: LogoLocationEnum
9
+ logoUrl?: string
10
+ isPreview?: boolean
11
+ }) {
12
+ const [logoFailed, setLogoFailed] = useState(false)
13
+
14
+ if (!logoUrl || logoFailed)
15
+ return (
16
+ <div className="w-full py-1.5 rounded-md flex items-center justify-center text-danger italic text-lg font-bold">
17
+ [Company Logo]
18
+ </div>
19
+ )
20
+
21
+ const imgClassName =
22
+ location === LogoLocationEnum.Authenticated
23
+ ? 'w-auto h-auto max-w-[140px] sm:max-w-[160px] md:max-w-[180px] lg:max-w-[200px] xl:max-w-[220px]'
24
+ : 'h-10 object-contain'
25
+
26
+ return (
27
+ <img
28
+ alt="Logo"
29
+ src={logoUrl}
30
+ style={{ maxWidth: isPreview ? '200px' : undefined }}
31
+ className={imgClassName}
32
+ onError={() => setLogoFailed(true)}
33
+ />
34
+ )
35
+ }
36
+
37
+ export enum LogoLocationEnum {
38
+ Authenticated,
39
+ Unauthenticated,
40
+ }
@@ -2,6 +2,7 @@ import { Button, Col, Form, Input, Row, Spin } from 'antd'
2
2
  import { useNavigate } from 'react-router-dom'
3
3
  import { useLoginHandler } from '../../common/custom-hooks/use-login-handler'
4
4
  import { useConfigContext } from '../context'
5
+ import CompanyLogoSection, { LogoLocationEnum } from '../../common/company-logo'
5
6
 
6
7
  export const ForgotPassword = () => {
7
8
  const { config } = useConfigContext()
@@ -11,7 +12,6 @@ export const ForgotPassword = () => {
11
12
  const formPadding = config?.loginLayout?.form?.padding
12
13
  const titleColor = config?.loginLayout.form.color
13
14
  const background = config?.loginLayout?.background
14
- const logoUrl = config?.siteIdentity?.logoUrl
15
15
  const primaryColor = config?.siteLayout?.siteConfigs?.colors?.primary
16
16
 
17
17
  return (
@@ -26,11 +26,9 @@ export const ForgotPassword = () => {
26
26
  maxWidth: '100%',
27
27
  }}
28
28
  >
29
- {logoUrl && (
30
- <div className="flex justify-center mb-4">
31
- <img src={logoUrl} alt="Logo" className="h-10 object-contain" />
32
- </div>
33
- )}
29
+ <div className="flex justify-center mb-4">
30
+ <CompanyLogoSection logoUrl={config?.siteIdentity?.logoUrl} location={LogoLocationEnum.Unauthenticated} />
31
+ </div>
34
32
 
35
33
  <div className="font-bold mb-2" style={{ color: titleColor }}>
36
34
  Forgot Password?
@@ -3,6 +3,7 @@ import { useConfigContext } from '../context'
3
3
  import { useLoginHandler } from '../../common/custom-hooks/use-login-handler'
4
4
  import { FaPlus } from 'react-icons/fa'
5
5
  import { useNavigate } from 'react-router-dom'
6
+ import CompanyLogoSection, { LogoLocationEnum } from '../../common/company-logo'
6
7
 
7
8
  export function UnauthenticatedLayout() {
8
9
  const { config } = useConfigContext()
@@ -23,7 +24,7 @@ export function UnauthenticatedLayout() {
23
24
 
24
25
  const logo = (
25
26
  <div className="flex justify-center">
26
- <img src={siteIdentity?.logoUrl} alt="Logo" className="h-10 object-contain" />
27
+ <CompanyLogoSection logoUrl={siteIdentity?.logoUrl} location={LogoLocationEnum.Unauthenticated} />
27
28
  </div>
28
29
  )
29
30
 
@@ -43,7 +44,9 @@ export function UnauthenticatedLayout() {
43
44
 
44
45
  const formSection = (
45
46
  <div
46
- className={`fc-login-container ${loginLayout?.layout === 'center' ? 'w-full' : 'w-1/2'} flex items-center justify-center h-screen`}
47
+ className={`fc-login-container ${
48
+ loginLayout?.layout === 'center' ? 'w-full' : 'w-1/2'
49
+ } flex items-center justify-center h-screen`}
47
50
  >
48
51
  <div
49
52
  style={{
@@ -57,7 +60,7 @@ export function UnauthenticatedLayout() {
57
60
  padding: `${loginLayout?.form?.padding || 16}px`,
58
61
  background: loginLayout?.form?.background,
59
62
  }}
60
- className={`fc-login-panel max-h-screen overflow-auto shadow content-center text-center ${
63
+ className={`fc-login-panel max-h-screen overflow-auto shadow content-center text-center space-y-4 ${
61
64
  loginLayout?.formStyle === 'full' ? 'h-screen' : ''
62
65
  }`}
63
66
  >
@@ -75,7 +78,7 @@ export function UnauthenticatedLayout() {
75
78
  {loginLayout?.form?.title}
76
79
  </div>
77
80
  )}
78
- <Form layout="vertical" onFinish={handleLogin} className='fc-login-form'>
81
+ <Form layout="vertical" onFinish={handleLogin} className="fc-login-form">
79
82
  <div>
80
83
  {loginLayout?.form?.fields?.map((field, index) => {
81
84
  const isLast = index === loginLayout?.form.fields.length - 1
@@ -140,7 +143,7 @@ export function UnauthenticatedLayout() {
140
143
  </div>
141
144
  </Form>
142
145
 
143
- {loginLayout?.logoPosition === 'bottom' && <div className='fc-login-logo'>{logo}</div>}
146
+ {loginLayout?.logoPosition === 'bottom' && <div className="fc-login-logo">{logo}</div>}
144
147
  </div>
145
148
  </div>
146
149
  )
@@ -4,6 +4,7 @@ import { useNavigate, useLocation } from 'react-router-dom'
4
4
  import { useLoginHandler } from '../../common/custom-hooks/use-login-handler'
5
5
  import { useConfigContext } from '../context'
6
6
  import { useRef } from 'react'
7
+ import CompanyLogoSection, { LogoLocationEnum } from '../../common/company-logo'
7
8
 
8
9
  export const ResetPassword = () => {
9
10
  const { config } = useConfigContext()
@@ -21,7 +22,6 @@ export const ResetPassword = () => {
21
22
  const formPadding = config?.loginLayout?.form?.padding
22
23
  const titleColor = config?.loginLayout.form.color
23
24
  const background = config?.loginLayout?.background
24
- const logoUrl = config?.siteIdentity?.logoUrl
25
25
  const primaryColor = config?.siteLayout?.siteConfigs?.colors?.primary
26
26
  const isFirstLoad = useRef(true)
27
27
  useEffect(() => {
@@ -64,11 +64,9 @@ export const ResetPassword = () => {
64
64
  maxWidth: '100%',
65
65
  }}
66
66
  >
67
- {logoUrl && (
68
- <div className="flex justify-center mb-4">
69
- <img src={logoUrl} alt="Logo" className="h-10 object-contain" />
70
- </div>
71
- )}
67
+ <div className="flex justify-center mb-4">
68
+ <CompanyLogoSection logoUrl={config?.siteIdentity?.logoUrl} location={LogoLocationEnum.Unauthenticated} />
69
+ </div>
72
70
 
73
71
  <div className="font-bold mb-2" style={{ color: titleColor }}>
74
72
  Reset Password
@@ -1,6 +1,6 @@
1
- import { ReactNode, useState } from 'react'
1
+ import { ReactNode, useState, useTransition } from 'react'
2
2
  import { IFormDndLayoutRowHeader } from '../../../../types'
3
- import { Collapse } from 'antd'
3
+ import { Collapse, Spin } from 'antd'
4
4
  import RowHeader from './header'
5
5
 
6
6
  export const LayoutRowConditionalHeaderRenderer = ({
@@ -11,21 +11,30 @@ export const LayoutRowConditionalHeaderRenderer = ({
11
11
  header: IFormDndLayoutRowHeader | undefined
12
12
  }) => {
13
13
  const [isCollapsed, setIsCollapsed] = useState(false)
14
+ const [isPendingTransition, startTransition] = useTransition()
14
15
 
15
16
  if (header?.isCollapsible)
16
17
  return (
17
- <Collapse
18
- className="fc-collapsible-row bg-transparent"
19
- bordered={false}
20
- defaultActiveKey={[]}
21
- items={[
22
- {
23
- key: '1',
24
- label: <RowHeader {...header} isCollapsed={isCollapsed} setIsCollapsed={() => setIsCollapsed((c) => !c)} />,
25
- children,
26
- },
27
- ]}
28
- />
18
+ <Spin spinning={isPendingTransition}>
19
+ <Collapse
20
+ className="fc-collapsible-row bg-transparent"
21
+ bordered={false}
22
+ defaultActiveKey={header.defaultCollapsed ? [] : ['1']}
23
+ items={[
24
+ {
25
+ key: '1',
26
+ label: (
27
+ <RowHeader
28
+ {...header}
29
+ isCollapsed={isCollapsed}
30
+ setIsCollapsed={() => startTransition(() => setIsCollapsed((c) => !c))}
31
+ />
32
+ ),
33
+ children,
34
+ },
35
+ ]}
36
+ />
37
+ </Spin>
29
38
  )
30
39
 
31
40
  if (header?.name)
@@ -1,4 +1,4 @@
1
- import { Form, Input, Upload } from 'antd'
1
+ import { Form, Input, Spin, Upload } from 'antd'
2
2
  import { useCallback, useState } from 'react'
3
3
  import { Button_FillerPortal } from '../../../common/button'
4
4
  import client from '../../../../api/client'
@@ -65,14 +65,10 @@ export default function LayoutRenderer_FileUpload({
65
65
 
66
66
  return (
67
67
  <>
68
- <Form.Item
69
- name={formItem.name}
70
- labelAlign="left"
71
- className="hidden"
72
- label={elementProps.hasNoLabel ? '' : elementProps.label}
73
- >
68
+ <Form.Item name={formItem.name} labelAlign="left" className="hidden">
74
69
  <Input />
75
70
  </Form.Item>
71
+ {!elementProps.hasNoLabel && elementProps.label && <span>{elementProps.label}</span>}
76
72
  {savedSignatureBlobName ? (
77
73
  <div
78
74
  className={`${ELEMENTS_DEFAULT_CLASS.Upload} text-primary flex items-center gap-2 bg-white rounded w-max px-4 py-1 font-semibold`}
@@ -96,20 +92,24 @@ export default function LayoutRenderer_FileUpload({
96
92
  </Button_FillerPortal>
97
93
  </div>
98
94
  ) : elementProps.isDragger ? (
99
- <Upload.Dragger {...uploadProps} disabled={isDisabled} beforeUpload={(file) => beforeUpload(file)}>
100
- <div className="flex flex-col items-center">
101
- <FaUpload size={24} className="text-primary" />
102
- <span className="font-semibold mt-2">{elementProps.placeholder}</span>
103
- <span className="text-opacity-50">{elementProps.hint}</span>
104
- </div>
105
- </Upload.Dragger>
95
+ <Spin size="small" spinning={loading}>
96
+ <Upload.Dragger {...uploadProps} disabled={isDisabled} beforeUpload={(file) => beforeUpload(file)}>
97
+ <div className="flex flex-col items-center">
98
+ <FaUpload size={24} className="text-primary" />
99
+ <span className="font-semibold mt-2">{elementProps.placeholder}</span>
100
+ <span className="text-opacity-50">{elementProps.hint}</span>
101
+ </div>
102
+ </Upload.Dragger>
103
+ </Spin>
106
104
  ) : (
107
- <Upload {...uploadProps} disabled={isDisabled} beforeUpload={(file) => beforeUpload(file)}>
108
- <Button_FillerPortal disabled={isDisabled} outline onClick={() => {}}>
109
- <FaUpload />
110
- {elementProps.placeholder}
111
- </Button_FillerPortal>
112
- </Upload>
105
+ <Spin size="small" spinning={loading}>
106
+ <Upload {...uploadProps} disabled={isDisabled} beforeUpload={(file) => beforeUpload(file)}>
107
+ <Button_FillerPortal disabled={isDisabled} outline onClick={() => {}} className="w-full">
108
+ <FaUpload />
109
+ {elementProps.placeholder}
110
+ </Button_FillerPortal>
111
+ </Upload>
112
+ </Spin>
113
113
  )}
114
114
  </>
115
115
  )
@@ -228,7 +228,7 @@ export default function LayoutRenderer_FieldsWithOptions({
228
228
  <LayoutRenderer_FieldElement formRef={formRef}>
229
229
  {() => ({
230
230
  ...props,
231
- label: (
231
+ label: props.label && (
232
232
  <div className="flex items-center gap-2 w-full">
233
233
  <span>{props.label}</span>
234
234
  {(props as ISelectElementProps).goToDetails?.enabled &&
@@ -179,10 +179,13 @@ const renderImageData = (imgFullUrl: string, renderConfig: IDataRender_Image) =>
179
179
  const renderTags = (data: string[]) => {
180
180
  if (!Array.isArray(data)) return '-'
181
181
 
182
+ console.log(data)
182
183
  return (
183
- <div className="flex flex-wrap gap-x-2 gap-y-1">
184
- {data.map((str) => (
185
- <span className="bg-gray-200 px-2 rounded-lg text-[11px]">{str}</span>
184
+ <div className="space-x-2">
185
+ {data.map((str, strIdx) => (
186
+ <span key={strIdx} className="bg-gray-200 px-2 py-0.5 rounded-lg text-[11px]">
187
+ {str}
188
+ </span>
186
189
  ))}
187
190
  </div>
188
191
  )
@@ -11,6 +11,7 @@ import { UserAuth } from '../../../../api/user'
11
11
  import { useBreadcrumb } from '../../../../components/common/custom-hooks/use-breadcrumb.hook'
12
12
  import { PageViewTypEnum } from '../../../../enums'
13
13
  import { REACT_QUERY_CLIENT } from '../../../../constants'
14
+ import CompanyLogoSection from '../../../../components/common/company-logo'
14
15
 
15
16
  const { Header, Content, Sider } = Layout
16
17
 
@@ -147,14 +148,7 @@ export const layoutTemplates = [
147
148
  {/* Logo */}
148
149
  <div className="flex fc-logo">
149
150
  <a href="/">
150
- <img
151
- alt="logo"
152
- src={config?.siteIdentity?.logoUrl}
153
- style={{
154
- maxWidth: isPreview ? '200px' : undefined,
155
- }}
156
- className="w-auto h-auto max-w-[140px] sm:max-w-[160px] md:max-w-[180px] lg:max-w-[200px] xl:max-w-[220px]"
157
- />
151
+ <CompanyLogoSection logoUrl={config?.siteIdentity?.logoUrl} isPreview={isPreview} />
158
152
  </a>
159
153
  {/* Mobile Menu */}
160
154
  <Drawer
@@ -348,14 +342,7 @@ export const layoutTemplates = [
348
342
  {/* Logo */}
349
343
  <div className="flex">
350
344
  <a href="/">
351
- <img
352
- alt="logo"
353
- src={config?.siteIdentity?.logoUrl}
354
- style={{
355
- maxWidth: isPreview ? '200px' : undefined,
356
- }}
357
- className="w-auto h-auto max-w-[140px] sm:max-w-[160px] md:max-w-[180px] lg:max-w-[200px] xl:max-w-[220px]"
358
- />
345
+ <CompanyLogoSection logoUrl={config?.siteIdentity?.logoUrl} isPreview={isPreview} />
359
346
  </a>
360
347
  {/* Mobile Menu */}
361
348
  <Drawer
@@ -556,6 +543,7 @@ export const layoutTemplates = [
556
543
  ))}
557
544
  </Menu>
558
545
  )
546
+
559
547
  return (
560
548
  <Layout className="fc-layout min-h-screen">
561
549
  {/* Side Menu */}
@@ -570,14 +558,7 @@ export const layoutTemplates = [
570
558
  {!isCollapsed && (
571
559
  <div className="flex justify-center p-2 fc-logo">
572
560
  <a href="/" className="w-full flex justify-center">
573
- <img
574
- alt="logo"
575
- src={config?.siteIdentity?.logoUrl}
576
- style={{
577
- maxWidth: isPreview ? '200px' : undefined,
578
- }}
579
- className="w-auto h-auto max-w-[140px] sm:max-w-[160px] md:max-w-[180px] lg:max-w-[200px] xl:max-w-[220px]"
580
- />
561
+ <CompanyLogoSection logoUrl={config?.siteIdentity?.logoUrl} isPreview={isPreview} />
581
562
  </a>
582
563
  </div>
583
564
  )}
@@ -641,14 +622,7 @@ export const layoutTemplates = [
641
622
  {/* Logo */}
642
623
  <div className="flex p-2 fc-logo">
643
624
  <a href="/">
644
- <img
645
- alt="logo"
646
- src={config?.siteIdentity?.logoUrl}
647
- style={{
648
- maxWidth: isPreview ? '200px' : undefined,
649
- }}
650
- className="w-auto h-auto max-w-[140px] sm:max-w-[160px] md:max-w-[180px] lg:max-w-[200px] xl:max-w-[220px]"
651
- />
625
+ <CompanyLogoSection logoUrl={config?.siteIdentity?.logoUrl} isPreview={isPreview} />
652
626
  </a>
653
627
  </div>
654
628
  {/* Mobile Menu Button */}
@@ -47,6 +47,7 @@ export interface IFormGenerateConfig {
47
47
 
48
48
  export interface IFormDndLayoutRowHeader {
49
49
  isCollapsible?: boolean
50
+ defaultCollapsed?: boolean
50
51
  name?: string
51
52
  style?: { [key: string]: string | number }
52
53
  }