datastake-daf 0.6.121 → 0.6.123

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.
@@ -0,0 +1,167 @@
1
+ import React, { useState } from 'react';
2
+ import { Button, Space } from 'antd';
3
+ import { CheckOutlined, ScanOutlined, FileTextOutlined, CheckCircleOutlined, LockOutlined } from '@ant-design/icons';
4
+ import ProgressTabs from './index';
5
+
6
+ const ProgressTabsDemo = () => {
7
+ const [value, setValue] = useState('setup');
8
+
9
+ const options = [
10
+ { label: 'Set Up', value: 'setup' },
11
+ { label: 'Project Scan', value: 'scan' },
12
+ { label: 'Review & Submission', value: 'review' },
13
+ { label: 'Submission Status', value: 'status' }
14
+ ];
15
+
16
+ const currentOption = options.find(option => option.value === value);
17
+ const currentIndex = options.findIndex(option => option.value === value);
18
+
19
+ const handleNext = () => {
20
+ const nextIndex = Math.min(options.length - 1, currentIndex + 1);
21
+ setValue(options[nextIndex].value);
22
+ };
23
+
24
+ const handlePrevious = () => {
25
+ const prevIndex = Math.max(0, currentIndex - 1);
26
+ setValue(options[prevIndex].value);
27
+ };
28
+
29
+ const handleValueChange = (newValue) => {
30
+ setValue(newValue);
31
+ };
32
+
33
+ return (
34
+ <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
35
+ <h2>ProgressTabs Component Demo</h2>
36
+ <p>This component creates a horizontal progress bar with clickable segments, similar to the design you provided. It uses Ant Design&apos;s Segmented component as the base.</p>
37
+
38
+ <div style={{ marginBottom: '20px' }}>
39
+ <ProgressTabs
40
+ value={value}
41
+ options={options}
42
+ onChange={handleValueChange}
43
+ />
44
+ </div>
45
+
46
+ <div style={{ textAlign: 'center', marginBottom: '20px' }}>
47
+ <p><strong>Current Step:</strong> {currentOption?.label}</p>
48
+ <p><strong>Step Value:</strong> {value}</p>
49
+ <p><strong>Step Index:</strong> {currentIndex}</p>
50
+ </div>
51
+
52
+ <Space>
53
+ <Button
54
+ onClick={handlePrevious}
55
+ disabled={value === 'setup'}
56
+ >
57
+ Previous
58
+ </Button>
59
+ <Button
60
+ type="primary"
61
+ onClick={handleNext}
62
+ disabled={value === 'status'}
63
+ >
64
+ Next
65
+ </Button>
66
+ </Space>
67
+
68
+ <div style={{ marginTop: '30px' }}>
69
+ <h3>Usage Example:</h3>
70
+ <pre style={{
71
+ background: '#f5f5f5',
72
+ padding: '15px',
73
+ borderRadius: '4px',
74
+ overflow: 'auto'
75
+ }}>
76
+ {`import { ProgressTabs } from 'datastake-daf/dist/components';
77
+ import { CheckOutlined, ScanOutlined, FileTextOutlined, CheckCircleOutlined } from '@ant-design/icons';
78
+
79
+ const MyComponent = () => {
80
+ const [value, setValue] = useState('setup');
81
+
82
+ const options = [
83
+ { label: 'Set Up', value: 'setup', icon: <CheckOutlined /> },
84
+ { label: 'Project Scan', value: 'scan', icon: <ScanOutlined />, isDisabled: true },
85
+ { label: 'Review & Submission', value: 'review', icon: <FileTextOutlined />, isDisabled: true },
86
+ { label: 'Submission Status', value: 'status', icon: <CheckCircleOutlined />, isDisabled: true }
87
+ ];
88
+
89
+ return (
90
+ <ProgressTabs
91
+ value={value}
92
+ options={options}
93
+ onChange={setValue}
94
+ width="100%" // Default is 100%, can be customized
95
+ />
96
+ );
97
+ };`}
98
+ </pre>
99
+ </div>
100
+
101
+ <div style={{ marginTop: '20px' }}>
102
+ <h3>Advanced Examples:</h3>
103
+
104
+ <div style={{ marginBottom: '20px' }}>
105
+ <h4>With Icons:</h4>
106
+ <ProgressTabs
107
+ value="setup"
108
+ options={[
109
+ { label: 'Set Up', value: 'setup', icon: <CheckOutlined /> },
110
+ { label: 'Project Scan', value: 'scan', icon: <ScanOutlined /> },
111
+ { label: 'Review & Submission', value: 'review', icon: <FileTextOutlined /> },
112
+ { label: 'Submission Status', value: 'status', icon: <CheckCircleOutlined /> }
113
+ ]}
114
+ />
115
+ </div>
116
+
117
+ <div style={{ marginBottom: '20px' }}>
118
+ <h4>With Disabled States:</h4>
119
+ <ProgressTabs
120
+ value="setup"
121
+ options={[
122
+ { label: 'Set Up', value: 'setup' },
123
+ { label: 'Project Scan', value: 'scan', isDisabled: true },
124
+ { label: 'Review & Submission', value: 'review', isDisabled: true },
125
+ { label: 'Submission Status', value: 'status', isDisabled: true }
126
+ ]}
127
+ />
128
+ </div>
129
+
130
+ <div style={{ marginBottom: '20px' }}>
131
+ <h4>With Icons and Disabled States:</h4>
132
+ <ProgressTabs
133
+ value="setup"
134
+ options={[
135
+ { label: 'Set Up', value: 'setup', icon: <CheckOutlined /> },
136
+ { label: 'Project Scan', value: 'scan', icon: <ScanOutlined />, isDisabled: true },
137
+ { label: 'Review & Submission', value: 'review', icon: <FileTextOutlined />, isDisabled: true },
138
+ { label: 'Submission Status', value: 'status', icon: <CheckCircleOutlined />, isDisabled: true }
139
+ ]}
140
+ />
141
+ </div>
142
+
143
+ <div style={{ marginBottom: '20px' }}>
144
+ <h4>Custom Width (400px):</h4>
145
+ <ProgressTabs
146
+ value="scan"
147
+ options={options}
148
+ width="400px"
149
+ />
150
+ </div>
151
+
152
+ <div style={{ marginBottom: '20px' }}>
153
+ <h4>Small Width (300px):</h4>
154
+ <ProgressTabs
155
+ value="review"
156
+ options={options}
157
+ width="300px"
158
+ />
159
+ </div>
160
+ </div>
161
+
162
+
163
+ </div>
164
+ );
165
+ };
166
+
167
+ export default ProgressTabsDemo;
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Segmented } from 'antd';
4
+ import './_index.scss';
5
+
6
+ const ProgressTabs = ({
7
+ value = 'setup',
8
+ options = [
9
+ { label: 'Set Up', value: 'setup' },
10
+ { label: 'Project Scan', value: 'scan' },
11
+ { label: 'Review & Submission', value: 'review' },
12
+ { label: 'Submission Status', value: 'status' }
13
+ ],
14
+ onChange = () => {},
15
+ className = '',
16
+ width = '100%',
17
+ ...rest
18
+ }) => {
19
+ // Transform options to include icons and handle disabled state
20
+ const transformedOptions = options.map(option => ({
21
+ ...option,
22
+ label: (
23
+ <div className="progress-tabs__option-content">
24
+
25
+ <span className="progress-tabs__label">
26
+ {option.label}
27
+ </span>
28
+ {option.icon && (
29
+ <span className="progress-tabs__icon">
30
+ {option.icon}
31
+ </span>
32
+ )}
33
+ </div>
34
+ ),
35
+ disabled: option.isDisabled || false,
36
+ }));
37
+
38
+ return (
39
+ <div
40
+ className={`progress-tabs ${className}`}
41
+ style={{ width }}
42
+ >
43
+ <Segmented
44
+ value={value}
45
+ options={transformedOptions}
46
+ onChange={onChange}
47
+ className="progress-tabs__segmented"
48
+ {...rest}
49
+ />
50
+ </div>
51
+ );
52
+ };
53
+
54
+ ProgressTabs.propTypes = {
55
+ value: PropTypes.string,
56
+ options: PropTypes.arrayOf(
57
+ PropTypes.shape({
58
+ label: PropTypes.string.isRequired,
59
+ value: PropTypes.string.isRequired,
60
+ isDisabled: PropTypes.bool,
61
+ icon: PropTypes.node,
62
+ })
63
+ ),
64
+ onChange: PropTypes.func,
65
+ className: PropTypes.string,
66
+ width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
67
+ };
68
+
69
+ export default ProgressTabs;
@@ -10,4 +10,5 @@
10
10
  @import './DynamicForm/index';
11
11
  @import "./Badge/index.scss";
12
12
  @import "./Screens/index.scss";
13
+ @import "./ProgressTabs/index";
13
14
  @import "./PdfForm/style.scss";
package/src/index.js CHANGED
@@ -69,7 +69,6 @@ export { default as DafDashboardDetails } from "./@daf/core/components/Dashboard
69
69
  export { default as KeyIndicatorsDetails } from "./@daf/core/components/Dashboard/Widget/Details/KeyIndicatorsDetails.jsx";
70
70
  export { default as DetailsSection } from "./@daf/core/components/Dashboard/Widget/DetailsSection/index.jsx";
71
71
  export { default as ComponentWithFocus } from "./@daf/core/components/Dashboard/ComponentWithFocus/index.jsx";
72
- export { default as WidgetCatalogue } from "./@daf/core/components/Dashboard/Widget/WidgetCatalogue/index.jsx";
73
72
 
74
73
  // Forms
75
74
  export { default as ViewForm } from "./@daf/core/components/ViewForm/content.jsx";
@@ -85,6 +84,7 @@ export { AjaxSelectMain as AjaxSelect } from "./@daf/core/components/EditForm/co
85
84
  export { default as ProgressBar } from "./@daf/core/components/ProgressBar/index.jsx";
86
85
  export { default as MultiBarProgress } from "./@daf/core/components/ProgressBar/MultiBarProgress/index.jsx";
87
86
  export { default as ProgressBarSideIcon } from "./@daf/core/components/ProgressBar/components/SideIcon/index.jsx";
87
+ export { default as ProgressTabs } from "./@daf/core/components/ProgressTabs/index.jsx";
88
88
 
89
89
  // Data Store
90
90
  export { default as DataStore } from "./@daf/core/components/DataStore/index.js";
@@ -1,109 +0,0 @@
1
- import React from "react";
2
- import WidgetCatalogue from "./index.jsx";
3
-
4
- // Sample projects data matching the image exactly
5
- const sampleProjects = [
6
- {
7
- title: "ABC Mangrove Senegal",
8
- image:
9
- "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=200&fit=crop",
10
- country: "Senegal",
11
- countryFlag: "https://flagcdn.com/w40/sn.png",
12
- sectoralScope: "AFOLU",
13
- methodology: "VM0033",
14
- imgAlt: "Mangrove landscape with calm water reflecting green trees",
15
- },
16
- {
17
- title: "IFM Jujuy",
18
- image:
19
- "https://images.unsplash.com/photo-1559827260-dc66d52bef19?w=400&h=200&fit=crop",
20
- country: "Argentina",
21
- countryFlag: "https://flagcdn.com/w40/ar.png",
22
- sectoralScope: "AFOLU",
23
- methodology: "VM0033",
24
- imgAlt: "White-faced whistling ducks in shallow water with green grass",
25
- },
26
- {
27
- title: "Sur del Meta",
28
- image:
29
- "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=200&fit=crop",
30
- country: "Colombia",
31
- countryFlag: "https://flagcdn.com/w40/co.png",
32
- sectoralScope: "AFOLU",
33
- methodology: "VM0033",
34
- imgAlt: "Aerial view of braided river channels through green landscape",
35
- },
36
- ];
37
-
38
- export default {
39
- title: "Dashboard/Widgets/WidgetCatalogue",
40
- component: WidgetCatalogue,
41
- parameters: {
42
- layout: "padded",
43
- docs: {
44
- description: {
45
- component:
46
- "A widget component that displays multiple project cards in a responsive grid layout, mapping over an array of project data. Each card shows project details including image, title, country, sectoral scope, methodology, and SDGs.",
47
- },
48
- },
49
- },
50
- argTypes: {
51
- title: {
52
- control: "text",
53
- description: "Widget title displayed at the top",
54
- },
55
- projects: {
56
- control: "object",
57
- description: "Array of project objects to display",
58
- },
59
- loading: {
60
- control: "boolean",
61
- description: "Loading state - shows spinner when true",
62
- },
63
- className: {
64
- control: "text",
65
- description: "Additional CSS classes for styling",
66
- },
67
- },
68
- };
69
-
70
- // Template for the story
71
- const Template = (args) => (
72
- <div
73
- style={{ padding: "20px", backgroundColor: "#f5f5f5", minHeight: "100vh" }}
74
- >
75
- <WidgetCatalogue {...args} />
76
- </div>
77
- );
78
-
79
- // Populated state - matches the image exactly
80
- export const Populated = Template.bind({});
81
- Populated.args = {
82
- title: "Project Catalogue",
83
- projects: sampleProjects,
84
- loading: false,
85
- };
86
- Populated.parameters = {
87
- docs: {
88
- description: {
89
- story:
90
- "Widget with multiple project cards, matching the design from the reference image. Shows three projects with images, country flags, and SDG icons.",
91
- },
92
- },
93
- };
94
-
95
- // Single project
96
- export const SingleProject = Template.bind({});
97
- SingleProject.args = {
98
- title: "Featured Project",
99
- projects: [sampleProjects[0]],
100
- loading: false,
101
- };
102
- SingleProject.parameters = {
103
- docs: {
104
- description: {
105
- story:
106
- "Widget with a single project card - shows how the grid adapts to fewer items.",
107
- },
108
- },
109
- };
@@ -1,197 +0,0 @@
1
- import React from "react";
2
- import { Image, Empty, Spin } from "antd";
3
- import { ExpandOutlined } from "@ant-design/icons";
4
- import { Card } from "antd";
5
- import Widget from "../index.jsx";
6
-
7
- // SDG configuration with proper colors and icons
8
- const SDG_CONFIG = {
9
- 1: {
10
- name: "No Poverty",
11
- color: "#E5243B",
12
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-01.jpg",
13
- },
14
- 2: {
15
- name: "Zero Hunger",
16
- color: "#DDA63A",
17
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-02.jpg",
18
- },
19
- 3: {
20
- name: "Good Health and Well-being",
21
- color: "#4C9F38",
22
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-03.jpg",
23
- },
24
- 4: {
25
- name: "Quality Education",
26
- color: "#C5192D",
27
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-04.jpg",
28
- },
29
- 6: {
30
- name: "Clean Water and Sanitation",
31
- color: "#26BDE2",
32
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-06.jpg",
33
- },
34
- 8: {
35
- name: "Decent Work and Economic Growth",
36
- color: "#A21942",
37
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-08.jpg",
38
- },
39
- 13: {
40
- name: "Climate Action",
41
- color: "#48773E",
42
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-13.jpg",
43
- },
44
- 15: {
45
- name: "Life on Land",
46
- color: "#3EB049",
47
- icon: "https://sdgs.un.org/sites/default/files/goals/E_SDG_Icons-15.jpg",
48
- },
49
- };
50
-
51
- // Default SDGs to show (matching the image)
52
- const DEFAULT_SDGS = [1, 2, 3, 4, 6, 8, 13, 15];
53
-
54
- // Individual Project Card Component
55
- const ProjectCard = ({
56
- title,
57
- image,
58
- imgAlt,
59
- country,
60
- countryFlag,
61
- sectoralScope,
62
- methodology,
63
- sdgs = [],
64
- }) => {
65
- return (
66
- <Card
67
- style={{
68
- minWidth: 280,
69
- width: "100%",
70
- borderRadius: "12px",
71
- overflow: "hidden",
72
- border: "1px solid #e5e7eb",
73
- boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
74
- }}
75
- cover={
76
- <div className="relative w-full h-40 overflow-hidden">
77
- {image ? (
78
- <img
79
- alt={imgAlt || `${title} image`}
80
- src={image}
81
- style={{ width: "100%", height: "100%", objectFit: "cover" }}
82
- />
83
- ) : (
84
- <div className="w-full h-full flex items-center justify-center bg-gray-100">
85
- <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
86
- </div>
87
- )}
88
- </div>
89
- }
90
- bodyStyle={{ padding: "16px" }}
91
- >
92
- {/* Title */}
93
- {title && (
94
- <h3 className="text-md font-semibold text-gray-900 mb-3">{title}</h3>
95
- )}
96
-
97
- {/* Country */}
98
- {country && (
99
- <div className="flex items-center justify-between py-2 border-b border-gray-200">
100
- <span className="text-sm text-gray-600">Country</span>
101
- <div className="flex items-center gap-1">
102
- {countryFlag && (
103
- <img
104
- src={countryFlag}
105
- alt={`${country} flag`}
106
- style={{ width: "16px", height: "12px" }}
107
- />
108
- )}
109
- <span className="text-sm font-medium text-gray-900">{country}</span>
110
- </div>
111
- </div>
112
- )}
113
-
114
- {/* Sectoral Scope */}
115
- {sectoralScope && (
116
- <div className="flex items-center justify-between py-2 border-b border-gray-200">
117
- <span className="text-sm text-gray-600">Sectoral Scope</span>
118
- <span className="text-sm font-medium text-gray-900">
119
- {sectoralScope}
120
- </span>
121
- </div>
122
- )}
123
-
124
- {/* Methodology */}
125
- {methodology && (
126
- <div className="flex items-center justify-between py-2 border-b border-gray-200">
127
- <span className="text-sm text-gray-600">Methodology</span>
128
- <span className="text-sm font-medium text-gray-900">
129
- {methodology}
130
- </span>
131
- </div>
132
- )}
133
-
134
- {/* SDGs */}
135
- <div className="pt-2">
136
- <span className="text-sm text-gray-600">SDGs</span>
137
- <div className="flex flex-wrap gap-1 mt-2">
138
- {(sdgs.length > 0 ? sdgs : DEFAULT_SDGS).map((sdg, index) => {
139
- const sdgConfig = typeof sdg === "number" ? SDG_CONFIG[sdg] : sdg;
140
- return (
141
- <img
142
- key={index}
143
- src={sdgConfig?.icon}
144
- alt={sdgConfig?.name}
145
- style={{ width: "22px", height: "22px", objectFit: "cover" }}
146
- />
147
- );
148
- })}
149
- </div>
150
- </div>
151
- </Card>
152
- );
153
- };
154
-
155
- // Main Widget Catalogue Component
156
- export default function WidgetCatalogue({
157
- title = "Project Catalogue",
158
- projects = [],
159
- loading = false,
160
- className = "",
161
- }) {
162
- if (loading) {
163
- return (
164
- <Widget title={title} className="with-border-header">
165
- <div className="flex justify-center items-center h-64">
166
- <Spin size="large" />
167
- </div>
168
- </Widget>
169
- );
170
- }
171
-
172
- return (
173
- <>
174
- <Widget title={title} className="with-border-header">
175
- <div
176
- style={{
177
- display: "flex",
178
- gap: "16px",
179
- justifyContent: "space-between",
180
- }}
181
- >
182
- {projects.slice(0, 3).map((project, idx) => (
183
- <div
184
- key={idx}
185
- style={{
186
- flex: "1 1 0", // make each card take equal width
187
- maxWidth: "calc(33.333% - 16px)",
188
- }}
189
- >
190
- <ProjectCard project={project} />
191
- </div>
192
- ))}
193
- </div>
194
- </Widget>
195
- </>
196
- );
197
- }