@banch0u/core-project-test-repository 1.0.30

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/.babelrc ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "presets": [
3
+ "@babel/preset-env",
4
+ "@babel/preset-react"
5
+ ],
6
+ "plugins": [
7
+ "@babel/plugin-transform-runtime"
8
+ ]
9
+ }
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ const core = require("./dist"); // Adjust path if needed
2
+ console.log(core);
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@banch0u/core-project-test-repository",
3
+ "version": "1.0.30",
4
+ "description": "Shared core features for all projects",
5
+ "main": "dist/index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/banch0u/core-project-test-repository.git"
9
+ },
10
+ "private": false,
11
+ "author": "banch0u",
12
+ "license": "MIT",
13
+ "scripts": {
14
+ "build": "npx babel src --out-dir dist --copy-files"
15
+ },
16
+ "dependencies": {
17
+ "@microsoft/signalr": "^8.0.7",
18
+ "@pdftron/webviewer": "^11.2.0",
19
+ "antd": "^5.16.0",
20
+ "react": "^18.2.0",
21
+ "react-dom": "^18.2.0",
22
+ "react-router-dom": "^6.16.0"
23
+ },
24
+ "devDependencies": {
25
+ "@babel/cli": "^7.26.4",
26
+ "@babel/core": "^7.26.9",
27
+ "@babel/plugin-transform-runtime": "^7.26.9",
28
+ "@babel/preset-env": "^7.26.9",
29
+ "@babel/preset-react": "^7.26.3",
30
+ "babel-loader": "^9.2.1"
31
+ }
32
+ }
@@ -0,0 +1,53 @@
1
+ @font-face {
2
+ font-family: "Inter";
3
+ src: url("./Inter/Inter-Thin.ttf") format("truetype");
4
+ font-weight: 100;
5
+ }
6
+
7
+ @font-face {
8
+ font-family: "Inter";
9
+ src: url("./Inter/Inter-ExtraLight.ttf") format("truetype");
10
+ font-weight: 200;
11
+ }
12
+
13
+ @font-face {
14
+ font-family: "Inter";
15
+ src: url("./Inter/Inter-Light.ttf") format("truetype");
16
+ font-weight: 300;
17
+ }
18
+
19
+ @font-face {
20
+ font-family: "Inter";
21
+ src: url("./Inter/Inter-Regular.ttf") format("truetype");
22
+ font-weight: 400;
23
+ }
24
+
25
+ @font-face {
26
+ font-family: "Inter";
27
+ src: url("./Inter/Inter-Medium.ttf") format("truetype");
28
+ font-weight: 500;
29
+ }
30
+
31
+ @font-face {
32
+ font-family: "Inter";
33
+ src: url("./Inter/Inter-SemiBold.ttf") format("truetype");
34
+ font-weight: 600;
35
+ }
36
+
37
+ @font-face {
38
+ font-family: "Inter";
39
+ src: url("./Inter/Inter-Bold.ttf") format("truetype");
40
+ font-weight: 700;
41
+ }
42
+
43
+ @font-face {
44
+ font-family: "Inter";
45
+ src: url("./Inter/Inter-ExtraBold.ttf") format("truetype");
46
+ font-weight: 800;
47
+ }
48
+
49
+ @font-face {
50
+ font-family: "Inter";
51
+ src: url("./Inter/Inter-Black.ttf") format("truetype");
52
+ font-weight: 900;
53
+ }
@@ -0,0 +1,72 @@
1
+ import React from "react";
2
+ export const SortIcon = () => {
3
+ return (
4
+ <svg
5
+ width="22"
6
+ height="22"
7
+ viewBox="0 0 22 22"
8
+ fill="none"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ >
11
+ <path
12
+ d="M2.75 6.41663H19.25"
13
+ stroke="#016DAF"
14
+ strokeWidth="1.375"
15
+ strokeLinecap="round"
16
+ />
17
+ <path
18
+ d="M5.5 11H16.5"
19
+ stroke="#016DAF"
20
+ strokeWidth="1.375"
21
+ strokeLinecap="round"
22
+ />
23
+ <path
24
+ d="M9.16675 15.5834H12.8334"
25
+ stroke="#016DAF"
26
+ strokeWidth="1.375"
27
+ strokeLinecap="round"
28
+ />
29
+ </svg>
30
+ );
31
+ };
32
+ export const FilterIcon = () => {
33
+ return (
34
+ <svg
35
+ width="24"
36
+ height="24"
37
+ viewBox="0 0 24 24"
38
+ fill="none"
39
+ xmlns="http://www.w3.org/2000/svg"
40
+ >
41
+ <path
42
+ d="M3.34985 2H12.2499C12.9899 2 13.5999 2.61001 13.5999 3.35001V4.82999C13.5999 5.36999 13.2599 6.04 12.9299 6.38L10.0299 8.94C9.62991 9.28 9.35986 9.94999 9.35986 10.49V13.39C9.35986 13.79 9.08988 14.33 8.74988 14.54L7.80987 15.15C6.92987 15.69 5.71985 15.08 5.71985 14V10.43C5.71985 9.95999 5.44987 9.35001 5.17987 9.01001L2.61987 6.31C2.27987 5.97 2.00989 5.36999 2.00989 4.95999V3.41C1.99989 2.61 2.60985 2 3.34985 2Z"
43
+ stroke="#016DAF"
44
+ strokeWidth="1.5"
45
+ strokeMiterlimit="10"
46
+ strokeLinecap="round"
47
+ strokeLinejoin="round"
48
+ />
49
+ <path
50
+ d="M2 12V15C2 20 4 22 9 22H15C20 22 22 20 22 15V9C22 5.88 21.22 3.91999 19.41 2.89999C18.9 2.60999 17.88 2.38999 16.95 2.23999"
51
+ stroke="#016DAF"
52
+ strokeWidth="1.5"
53
+ strokeLinecap="round"
54
+ strokeLinejoin="round"
55
+ />
56
+ <path
57
+ d="M13 13H18"
58
+ stroke="#016DAF"
59
+ strokeWidth="1.5"
60
+ strokeLinecap="round"
61
+ strokeLinejoin="round"
62
+ />
63
+ <path
64
+ d="M11 17H18"
65
+ stroke="#016DAF"
66
+ strokeWidth="1.5"
67
+ strokeLinecap="round"
68
+ strokeLinejoin="round"
69
+ />
70
+ </svg>
71
+ );
72
+ };
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+ import style from "./index.module.scss";
3
+ const Button = ({
4
+ children,
5
+ onClick,
6
+ color = "blue",
7
+ disabled = false,
8
+ type,
9
+ }) => {
10
+ return (
11
+ <>
12
+ {color === "blue" ? (
13
+ <button
14
+ disabled={disabled}
15
+ type={type}
16
+ className={style.button}
17
+ onClick={onClick}>
18
+ {children}
19
+ </button>
20
+ ) : null}
21
+ {color === "white" ? (
22
+ <button
23
+ disabled={disabled}
24
+ type={type}
25
+ className={style.button_white}
26
+ onClick={onClick}>
27
+ {children}
28
+ </button>
29
+ ) : null}
30
+ {color === "green" ? (
31
+ <button
32
+ disabled={disabled}
33
+ type={type}
34
+ className={style.button_green}
35
+ onClick={onClick}>
36
+ {children}
37
+ </button>
38
+ ) : null}
39
+ {color === "green-white" ? (
40
+ <button
41
+ disabled={disabled}
42
+ type={type}
43
+ className={style.button_green_white}
44
+ onClick={onClick}>
45
+ {children}
46
+ </button>
47
+ ) : null}
48
+ {color === "red" ? (
49
+ <button
50
+ disabled={disabled}
51
+ type={type}
52
+ className={style.button_red}
53
+ onClick={onClick}>
54
+ {children}
55
+ </button>
56
+ ) : null}
57
+ </>
58
+ );
59
+ };
60
+
61
+ export default Button;
@@ -0,0 +1,142 @@
1
+ .button {
2
+ border-radius: 6px;
3
+ background: var(--darkBlueColor);
4
+ padding: 5px 10px;
5
+ font-size: 16px;
6
+ font-weight: 400;
7
+ line-height: 24px;
8
+ letter-spacing: 0.5px;
9
+ border: 1px solid var(--darkBlueColor);
10
+ color: #fff;
11
+ cursor: pointer;
12
+ transition: 250ms;
13
+
14
+ display: flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ gap: 8px;
18
+ svg {
19
+ path {
20
+ transition: 250ms;
21
+ }
22
+ }
23
+ }
24
+
25
+ .button:hover {
26
+ background: #005386;
27
+ border: 1px solid #005386;
28
+ transition: 250ms;
29
+ }
30
+ .button_white {
31
+ border-radius: 6px;
32
+ background: transparent;
33
+ padding: 5px 10px;
34
+ font-size: 16px;
35
+ font-weight: 400;
36
+ line-height: 24px;
37
+ letter-spacing: 0.5px;
38
+ border: 1px solid var(--darkBlueColor);
39
+ color: var(--darkBlueColor);
40
+ cursor: pointer;
41
+ transition: 250ms;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ gap: 8px;
46
+ svg {
47
+ path {
48
+ transition: 250ms;
49
+ }
50
+ }
51
+ }
52
+ .button_white:hover {
53
+ border: 1px solid gray;
54
+ color: gray;
55
+ transition: 250ms;
56
+ svg {
57
+ path {
58
+ transition: 250ms;
59
+ stroke: gray;
60
+ }
61
+ }
62
+ }
63
+ .button_white:disabled,
64
+ .button_white[disabled] {
65
+ cursor: not-allowed !important;
66
+ opacity: 0.5 !important;
67
+ border-color: gray !important;
68
+ color: gray !important;
69
+ }
70
+
71
+ .button_green {
72
+ border-radius: 6px;
73
+ background: #219653;
74
+ padding: 5px 10px;
75
+ font-size: 16px;
76
+ font-weight: 400;
77
+ line-height: 24px;
78
+ letter-spacing: 0.5px;
79
+ border: 1px solid #219653;
80
+ color: #fff;
81
+ cursor: pointer;
82
+ transition: 250ms;
83
+
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ gap: 8px;
88
+ svg {
89
+ path {
90
+ transition: 250ms;
91
+ }
92
+ }
93
+ }
94
+
95
+ .button_red {
96
+ border-radius: 6px;
97
+ background: #eb5757;
98
+ padding: 5px 10px;
99
+ font-size: 16px;
100
+ font-weight: 400;
101
+ line-height: 24px;
102
+ letter-spacing: 0.5px;
103
+ border: 1px solid #eb5757;
104
+ color: #fff;
105
+ cursor: pointer;
106
+ transition: 250ms;
107
+
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ gap: 8px;
112
+ svg {
113
+ path {
114
+ transition: 250ms;
115
+ }
116
+ }
117
+ }
118
+
119
+ .button_green_white {
120
+ border-radius: 6px;
121
+ background: transparent!important;
122
+ padding: 5px 10px;
123
+ font-size: 16px;
124
+ font-weight: 400;
125
+ line-height: 24px;
126
+ letter-spacing: 0.5px;
127
+ border: 1px solid #219653;
128
+ color: #fff;
129
+ cursor: pointer;
130
+ transition: 250ms;
131
+
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ gap: 8px;
136
+ svg {
137
+ path {
138
+ transition: 250ms;
139
+ fill: #219653!important;
140
+ }
141
+ }
142
+ }
@@ -0,0 +1,51 @@
1
+ import React, { useState } from "react";
2
+ import { Dropdown, Menu, Checkbox } from "antd";
3
+ import style from "./index.module.scss";
4
+ import { SortIcon } from "../../assets/icons";
5
+ import Button from "../Button";
6
+
7
+ const ColSort = ({ columns, selectedColumns, handleColumnToggle }) => {
8
+ const [visible, setVisible] = useState(false);
9
+
10
+ const handleVisibleChange = (isVisible) => {
11
+ setVisible(isVisible);
12
+ };
13
+
14
+ const menu = (
15
+ <Menu className={style.menu}>
16
+ {columns
17
+ .filter((col) => col.dataIndex !== "filterOnly") // Exclude columns with dataIndex === "filterOnly"
18
+ .map(
19
+ (col) =>
20
+ col.showCheckbox !== false && (
21
+ <Menu.Item key={col.title}>
22
+ <div className={style.menu_item}>
23
+ <Checkbox
24
+ disabled={col.disabled}
25
+ checked={selectedColumns.includes(col.dataIndex)}
26
+ onChange={(e) =>
27
+ handleColumnToggle(e.target.checked, col.dataIndex)
28
+ }
29
+ />
30
+ <span>{col.title}</span>
31
+ </div>
32
+ </Menu.Item>
33
+ )
34
+ )}
35
+ </Menu>
36
+ );
37
+
38
+ return (
39
+ <Dropdown
40
+ overlay={menu}
41
+ trigger={["click"]}
42
+ visible={visible}
43
+ onVisibleChange={handleVisibleChange}>
44
+ <Button color="white">
45
+ <SortIcon />
46
+ </Button>
47
+ </Dropdown>
48
+ );
49
+ };
50
+
51
+ export default ColSort;
@@ -0,0 +1,40 @@
1
+ .menu {
2
+ width: 254px;
3
+ padding: 10px !important;
4
+ padding-bottom: 5px !important;
5
+ box-shadow: 0px 4px 4px 0px #0000001a !important;
6
+ border: 1px solid #d1d1d1 !important;
7
+ background: #deeaf6 !important;
8
+
9
+ .count {
10
+ margin-bottom: 24px;
11
+ display: flex;
12
+ justify-content: space-between;
13
+ font-size: 14px;
14
+ font-weight: 500;
15
+ line-height: 21px;
16
+ }
17
+
18
+ li {
19
+ padding: 0 !important;
20
+ margin-bottom: 5px !important;
21
+ font-family: Inter !important;
22
+ font-size: 14px !important;
23
+ font-weight: 400 !important;
24
+ line-height: 21px !important;
25
+ letter-spacing: -0.4000000059604645px !important;
26
+ text-align: left !important;
27
+ }
28
+ .menu_item {
29
+ display: flex;
30
+ gap: 8px;
31
+ background: #fff;
32
+ padding: 6px;
33
+ border-radius: 4px;
34
+ }
35
+ }
36
+ .filter_icon {
37
+ cursor: pointer;
38
+ width: 22px;
39
+ height: 22px;
40
+ }
@@ -0,0 +1,220 @@
1
+ import React, { useState } from "react";
2
+ import {
3
+ Dropdown,
4
+ Menu,
5
+ Form,
6
+ Input,
7
+ Select,
8
+ DatePicker,
9
+ TreeSelect,
10
+ } from "antd";
11
+ import style from "./index.module.scss";
12
+ import Button from "../Button";
13
+ import { FilterIcon } from "../../assets/icons";
14
+
15
+ const { Option } = Select;
16
+ const { RangePicker } = DatePicker;
17
+
18
+ const Filter = ({
19
+ columns,
20
+ selectedColumns,
21
+ setQuery,
22
+ disabledElementCount,
23
+ setPage,
24
+ setSelectedTopic,
25
+ }) => {
26
+ const [filterForm] = Form.useForm();
27
+ const [visible, setVisible] = useState(false);
28
+
29
+ const handleOpenChange = (isOpen) => {
30
+ setVisible(isOpen);
31
+ };
32
+
33
+ const formatDate = (day, month, year) => {
34
+ const formattedDay = String(day).padStart(2, "0");
35
+ const formattedMonth = String(month).padStart(2, "0");
36
+ return `${formattedDay}.${formattedMonth}.${year}`;
37
+ };
38
+ const handleFinish = (values) => {
39
+ const formattedValues = { ...values };
40
+ Object.keys(values).forEach((key) => {
41
+ if (Array.isArray(values[key]) && values[key].length === 2) {
42
+ const [start, end] = values[key];
43
+ if (start && end) {
44
+ const formattedStart = formatDate(
45
+ start.date(),
46
+ start.month() + 1,
47
+ start.year()
48
+ );
49
+ const formattedEnd = formatDate(
50
+ end.date(),
51
+ end.month() + 1,
52
+ end.year()
53
+ );
54
+ formattedValues[key] = `${formattedStart} - ${formattedEnd}`;
55
+ }
56
+ }
57
+ });
58
+ setQuery(formattedValues);
59
+ setVisible(false);
60
+ };
61
+
62
+ // Filter the columns based on selectedColumns, filterDisable, and filter status
63
+ const filteredColumns = columns.filter(
64
+ (col) =>
65
+ (selectedColumns.includes(col.dataIndex) &&
66
+ col.filter !== false &&
67
+ col.filterDisable !== true) ||
68
+ col.dataIndex === "filterOnly" // Always include "filterOnly" columns in the filter
69
+ );
70
+
71
+ const getGrid = () => {
72
+ const elementCount = selectedColumns.length - disabledElementCount;
73
+ if (elementCount >= 5) return style.grid5;
74
+ if (elementCount === 4) return style.grid4;
75
+ if (elementCount === 3) return style.grid3;
76
+ if (elementCount === 2) return style.grid2;
77
+ if (elementCount === 1) return style.grid1;
78
+ };
79
+
80
+ const menu = (
81
+ <Menu className={style.menu}>
82
+ <div className="filter">
83
+ <Form
84
+ onFinish={handleFinish}
85
+ form={filterForm}
86
+ layout="vertical"
87
+ className={`${style.form} ${getGrid()}`}>
88
+ {[
89
+ ...filteredColumns.filter((col) => !col.isDouble), // Non-double elements
90
+ ...filteredColumns.filter((col) => col.isDouble), // Double elements
91
+ ].map((col) => {
92
+ if (col.showCheckbox === false) {
93
+ return null;
94
+ }
95
+
96
+ const gridSpanClass = col.isDouble
97
+ ? style.doubleGrid
98
+ : style.singleGrid;
99
+
100
+ if (col.type === "select") {
101
+ return (
102
+ <Form.Item
103
+ key={col.dataIndex}
104
+ label={col.title}
105
+ name={col.queryName ? col.queryName : col.dataIndex}
106
+ className={gridSpanClass} // Dynamically apply grid class
107
+ >
108
+ <Select
109
+ showSearch={col.isDouble} // Enable search for double items
110
+ onChange={(value) => {
111
+ if (col.dataIndex === "topic") {
112
+ setSelectedTopic(value);
113
+ }
114
+ }}
115
+ filterOption={(input, option) => {
116
+ if (!option || !option.children) return false; // Ensure option and children exist
117
+
118
+ const optionText = String(option.children); // Convert to string if needed
119
+ const normalizedInput = input.toLowerCase(); // Normalize input to lowercase
120
+ const normalizedOption = optionText
121
+ .replace(/İ/g, "I")
122
+ .toLowerCase(); // Normalize option text
123
+
124
+ return normalizedOption.includes(normalizedInput);
125
+ }}>
126
+ <Option value=""></Option>
127
+ {(col?.selectData || []).map((option, i) => {
128
+ const isIdArray = Array.isArray(option.id);
129
+ return (
130
+ <Option
131
+ key={i}
132
+ value={
133
+ isIdArray
134
+ ? JSON.stringify(option.id) // Convert array to string
135
+ : option.id // Use ID directly
136
+ }>
137
+ {option.name} {option.surname} {option.text}
138
+ {/* Display the name */}
139
+ </Option>
140
+ );
141
+ })}
142
+ </Select>
143
+ </Form.Item>
144
+ );
145
+ }
146
+ if (col.type === "date") {
147
+ return (
148
+ <Form.Item
149
+ key={col.dataIndex}
150
+ label={col.title}
151
+ name={col.queryName ? col.queryName : col.dataIndex}
152
+ className={gridSpanClass} // Dynamically apply grid class
153
+ >
154
+ <RangePicker format="DD.MM.YYYY" placeholder="" />
155
+ </Form.Item>
156
+ );
157
+ }
158
+ if (col.type === "recursive") {
159
+ return (
160
+ <Form.Item
161
+ key={col.dataIndex}
162
+ label={col.title}
163
+ name={col.queryName ? col.queryName : col.dataIndex}
164
+ className={gridSpanClass} // Dynamically apply grid class
165
+ >
166
+ <TreeSelect
167
+ // style={{ width: "230px", marginTop: "5px" }}
168
+ showSearch
169
+ popupMatchSelectWidth={false}
170
+ allowClear
171
+ treeDefaultExpandAll
172
+ treeData={col.selectData}
173
+ />
174
+ </Form.Item>
175
+ );
176
+ }
177
+ return (
178
+ <Form.Item
179
+ key={col.dataIndex}
180
+ label={col.title}
181
+ name={col.queryName ? col.queryName : col.dataIndex}
182
+ className={gridSpanClass} // Dynamically apply grid class
183
+ >
184
+ <Input />
185
+ </Form.Item>
186
+ );
187
+ })}
188
+ </Form>
189
+ <div className={style.buttons}>
190
+ <Button onClick={() => filterForm.resetFields()} color="white">
191
+ Təmizlə
192
+ </Button>
193
+ <Button
194
+ onClick={() => {
195
+ setPage(1);
196
+ filterForm.submit();
197
+ setVisible(false);
198
+ }}>
199
+ Axtar
200
+ </Button>
201
+ </div>
202
+ </div>
203
+ </Menu>
204
+ );
205
+
206
+ return (
207
+ <Dropdown
208
+ overlay={menu}
209
+ trigger={["click"]}
210
+ open={visible} // Updated to use open
211
+ onOpenChange={handleOpenChange} // Updated to use onOpenChange
212
+ >
213
+ <Button color="white">
214
+ <FilterIcon /> Filter menyu
215
+ </Button>
216
+ </Dropdown>
217
+ );
218
+ };
219
+
220
+ export default Filter;
@@ -0,0 +1,99 @@
1
+ .menu {
2
+ padding: 14px !important;
3
+ box-shadow: 0px 4px 4px 0px #0000001a;
4
+ background: #fff !important;
5
+
6
+ .form {
7
+ display: grid;
8
+ gap: 14px; // Space between items
9
+
10
+ &.grid5 {
11
+ grid-template-columns: repeat(5, minmax(170px, 1fr)); // 5 columns
12
+ }
13
+
14
+ &.grid4 {
15
+ grid-template-columns: repeat(4, minmax(170px, 1fr)); // 4 columns
16
+ }
17
+
18
+ &.grid3 {
19
+ grid-template-columns: repeat(3, minmax(170px, 1fr)); // 3 columns
20
+ }
21
+
22
+ &.grid2 {
23
+ grid-template-columns: repeat(2, minmax(170px, 1fr)); // 2 columns
24
+ }
25
+
26
+ &.grid1 {
27
+ grid-template-columns: repeat(1, minmax(170px, 1fr)); // 1 column
28
+ }
29
+
30
+ .singleGrid {
31
+ grid-column: span 1; // Single grid item takes one column
32
+ width: 170px; // Ensure single items are 170px wide
33
+ }
34
+
35
+ .doubleGrid {
36
+ grid-column: span 2; // Double grid item takes two columns
37
+ width: 334px; // Ensure double items are 334px wide
38
+ }
39
+
40
+ label {
41
+ font-family: Inter;
42
+ font-size: 14px;
43
+ font-weight: 400;
44
+ line-height: 16.94px;
45
+ text-align: left;
46
+ color: #646464;
47
+ }
48
+
49
+ .input,
50
+ .select,
51
+ .modal_date {
52
+ width: 100%; // Inherit width based on grid column
53
+ height: 34px;
54
+ border-radius: 6px;
55
+ padding: 8px 16px;
56
+ font-size: 16px;
57
+ font-weight: 500;
58
+ line-height: 24px;
59
+ text-align: left;
60
+ }
61
+
62
+ .select > div {
63
+ padding: 5px 16px !important;
64
+ border-radius: 6px !important;
65
+ height: 34px;
66
+ }
67
+
68
+ .select {
69
+ span {
70
+ font-size: 16px !important;
71
+ font-weight: 500 !important;
72
+ line-height: 24px !important;
73
+ text-align: left !important;
74
+ }
75
+ }
76
+
77
+ .modal_date {
78
+ input {
79
+ font-size: 16px !important;
80
+ font-weight: 500 !important;
81
+ line-height: 24px !important;
82
+ text-align: left !important;
83
+ }
84
+ }
85
+ }
86
+
87
+ .buttons {
88
+ display: flex;
89
+ justify-content: flex-end;
90
+ gap: 14px;
91
+ margin-top: 20px;
92
+ }
93
+ }
94
+
95
+ .filter_icon {
96
+ cursor: pointer;
97
+ width: 22px;
98
+ height: 22px;
99
+ }
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import style from "./index.module.scss";
3
+ import { Spin } from "antd";
4
+
5
+ const Loading = () => {
6
+ return (
7
+ <>
8
+ <div className={style.overlay}></div>
9
+ <div className={style.spinner}>
10
+ <Spin size="large" />
11
+ </div>
12
+ </>
13
+ );
14
+ };
15
+
16
+ export default Loading;
@@ -0,0 +1,18 @@
1
+ .spinner {
2
+ position: absolute;
3
+ top: 50%;
4
+ left: 50%;
5
+ transform: translate(-50%, -50%);
6
+ color: red !important;
7
+ z-index: 9999;
8
+ }
9
+
10
+ .overlay {
11
+ height: 100vh;
12
+ width: 100%;
13
+ position: absolute;
14
+ top: 0;
15
+ left: 0;
16
+ background: #ffffff50;
17
+ z-index: 9999;
18
+ }
@@ -0,0 +1,8 @@
1
+ .pagination {
2
+ margin-top: 10px;
3
+ }
4
+
5
+ .container {
6
+ display: flex;
7
+ align-items: center;
8
+ }
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { Select as AntSelect } from "antd";
3
+ import { counts } from "./constant";
4
+ const { Option } = AntSelect;
5
+
6
+ const Select = ({ setSize, size }) => {
7
+ const handleChange = (value) => {
8
+ setSize(value);
9
+ };
10
+
11
+ return (
12
+ <AntSelect
13
+ onChange={handleChange}
14
+ defaultValue={size}
15
+ style={{ width: 60, marginTop: "10px", marginLeft: "10px" }}
16
+ >
17
+ {counts.map((item) => (
18
+ <Option key={item.id} value={item.value}>
19
+ {item.value}
20
+ </Option>
21
+ ))}
22
+ </AntSelect>
23
+ );
24
+ };
25
+
26
+ export default Select;
@@ -0,0 +1,22 @@
1
+ export const counts = [
2
+ {
3
+ id: 1,
4
+ value: "10",
5
+ },
6
+ {
7
+ id: 2,
8
+ value: "20",
9
+ },
10
+ {
11
+ id: 3,
12
+ value: "30",
13
+ },
14
+ {
15
+ id: 4,
16
+ value: "40",
17
+ },
18
+ {
19
+ id: 5,
20
+ value: "50",
21
+ },
22
+ ];
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+ import { Pagination as AntPagination } from "antd";
3
+ import style from "./Pagination.module.scss";
4
+ import Select from "./Select";
5
+
6
+ const Pagination = ({ onChange, page = 1, size = 10, total = 0, setSize }) => {
7
+ const setPagination = (page) => {
8
+ onChange(page); // Trigger the page change callback
9
+
10
+ // Find the scrollable part of the Ant Table and scroll to the top
11
+ const tableBody = document.querySelector(".ant-table-body");
12
+ if (tableBody) {
13
+ tableBody.scrollTo({ top: 0, behavior: "smooth" });
14
+ }
15
+ };
16
+
17
+ return (
18
+ <div className={style.container}>
19
+ <AntPagination
20
+ className={style.pagination}
21
+ current={Number(page)} // Ensure numeric values
22
+ onChange={setPagination}
23
+ total={Number(total)} // Ensure numeric values
24
+ showSizeChanger={false}
25
+ />
26
+ <div className="pagination_select">
27
+ <Select size={size} setSize={setSize} style={{ marginTop: "10px" }} />
28
+ </div>
29
+ </div>
30
+ );
31
+ };
32
+
33
+ export default Pagination;
@@ -0,0 +1,57 @@
1
+ // hooks/useNotification.js
2
+ import { useEffect, useState } from "react";
3
+ import * as signalR from "@microsoft/signalr";
4
+ import { infoMessageBottomRight } from "../utils/message";
5
+
6
+ const useNotification = () => {
7
+ const [notifications, setNotifications] = useState(() => {
8
+ // localStorage'dan bildirimi başlat
9
+ const savedNotifications = localStorage.getItem("notifications");
10
+ return savedNotifications ? JSON.parse(savedNotifications) : [];
11
+ });
12
+
13
+ useEffect(() => {
14
+ const token = localStorage.getItem("token");
15
+ let baseUrl;
16
+ if (window.location.hostname === "localhost") {
17
+
18
+ baseUrl = process.env.REACT_APP_ROOT;
19
+ } else {
20
+ baseUrl = window.location.origin;
21
+ }
22
+ if (!token) {
23
+ console.error("Token tapılmadı!");
24
+ return;
25
+ }
26
+
27
+ const connection = new signalR.HubConnectionBuilder()
28
+ .withUrl(`${baseUrl}/notify?token=${token}`, {
29
+ transport:
30
+ signalR.HttpTransportType.WebSockets,
31
+ withCredentials: false,
32
+ skipNegotiation: true,
33
+ })
34
+ .configureLogging(signalR.LogLevel.Information)
35
+ .build();
36
+
37
+ connection
38
+ .start()
39
+ .then(() => {
40
+ console.log("SignalR bağlantısı quruldu.");
41
+ connection.on("receive", (message) => {
42
+ console.log("Yeni bildiriş:", message);
43
+ infoMessageBottomRight(message);
44
+ });
45
+ })
46
+ .catch((err) => console.error("SignalR bağlantısı qurula bilmədi:", err));
47
+
48
+ return () => {
49
+ connection.stop();
50
+ console.log("SignalR bağlantısı bağlandı.");
51
+ };
52
+ }, []);
53
+
54
+ return notifications;
55
+ };
56
+
57
+ export default useNotification;
package/src/index.js ADDED
@@ -0,0 +1,13 @@
1
+ // Export the Button component from the components directory as a named export
2
+ import "./assets/fonts/fonts.css";
3
+ export { default as Button } from "./components/Button";
4
+ export { default as ColSort } from "./components/ColSort";
5
+ export { default as Filter } from "./components/Filter";
6
+ export { default as Loading } from "./components/Loading";
7
+ export { default as Pagination } from "./components/Pagination";
8
+ export { default as useNotification } from "./hooks/useNotification";
9
+ export { default as message } from "./utils/message";
10
+
11
+
12
+
13
+
@@ -0,0 +1,37 @@
1
+ import { notification } from "antd";
2
+
3
+ const playNotificationSound = async () => {
4
+ const audio = new Audio("https://assets.mixkit.co/active_storage/sfx/2575/2575-preview.mp3");
5
+ audio.type = "audio/mpeg"; // Audio format
6
+ audio.preload = "auto";
7
+
8
+ setTimeout(() => {
9
+ audio.play().catch((error) => console.error("Audio play failed:", error));
10
+ }, 400);
11
+ };
12
+
13
+
14
+ export const errorMessage = ({ value, placeMent }) => {
15
+ return notification.error({
16
+ message: "",
17
+ description: value || "Serverdə problem baş verdi",
18
+ placement: placeMent,
19
+ });
20
+ };
21
+
22
+ export const succesMessage = (value) => {
23
+ return notification.success({
24
+ message: "",
25
+ description: value || "Uğurla tamamlandı",
26
+ placement: "topRight",
27
+ });
28
+ };
29
+
30
+ export const infoMessageBottomRight = (value) => {
31
+ playNotificationSound();
32
+ return notification.info({
33
+ message: "Yeni bildiriş",
34
+ description: value || "Bildiriş",
35
+ placement: "bottomRight",
36
+ });
37
+ };
@@ -0,0 +1,35 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+ entry: './src/index.js', // Your entry file where your components are exported
5
+ output: {
6
+ path: path.resolve(__dirname, 'dist'),
7
+ filename: 'bundle.js', // Your output bundle
8
+ library: '@banch0u/core-project-test-repository', // Exposes your components as a library
9
+ libraryTarget: 'umd', // Can be used in various environments like CommonJS, AMD, etc.
10
+ clean: true, // Cleans the dist folder before each build
11
+ },
12
+ resolve: {
13
+ extensions: ['.js', '.jsx'], // Resolve .js and .jsx files
14
+ },
15
+ module: {
16
+ rules: [
17
+ {
18
+ test: /\.jsx?$/, // Applies to JavaScript/JSX files
19
+ exclude: /node_modules/,
20
+ use: {
21
+ loader: 'babel-loader',
22
+ },
23
+ },
24
+ {
25
+ test: /\.scss$/, // Handles SCSS files
26
+ use: [
27
+ 'style-loader', // Adds styles to DOM
28
+ 'css-loader', // Translates CSS into CommonJS
29
+ 'sass-loader', // Compiles SCSS to CSS
30
+ ],
31
+ },
32
+ ],
33
+ },
34
+ devtool: 'source-map', // For better error tracking
35
+ };