albinasoft-ui-package 1.1.60 → 1.1.62
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.
@@ -22,6 +22,7 @@ export interface FileUploaderTranslations {
|
|
22
22
|
fileTypeError: string;
|
23
23
|
noFileSelectedWarning: string;
|
24
24
|
pendingBeforeSubmitWarning?: string;
|
25
|
+
requiredBeforeSubmitWarning?: string;
|
25
26
|
}
|
26
27
|
export declare const defaultTranslations: FileUploaderTranslations;
|
27
28
|
export interface CustomFileUploaderProps {
|
@@ -35,6 +36,8 @@ export interface CustomFileUploaderProps {
|
|
35
36
|
maxFile: number;
|
36
37
|
/** Her bir dosya için maksimum boyut (byte cinsinden) */
|
37
38
|
maxSize: number;
|
39
|
+
required?: boolean;
|
40
|
+
submitted?: boolean;
|
38
41
|
/**
|
39
42
|
* Opsiyonel: Yükleme tamamlandığında dönen dosya isimlerini almak için callback.
|
40
43
|
*/
|
@@ -112,7 +112,8 @@ exports.defaultTranslations = {
|
|
112
112
|
fileSizeError: "isimli dosya, boyut limitini aşıyor.",
|
113
113
|
fileTypeError: "isimli dosya, seçilen dosya türüne uygun değil.",
|
114
114
|
noFileSelectedWarning: "Önce en az bir dosya seçiniz.",
|
115
|
-
pendingBeforeSubmitWarning: "Henüz yüklenmemiş dosyalar var. Lütfen önce 'Yükle' butonuna basın."
|
115
|
+
pendingBeforeSubmitWarning: "Henüz yüklenmemiş dosyalar var. Lütfen önce 'Yükle' butonuna basın.",
|
116
|
+
requiredBeforeSubmitWarning: "En az bir dosya yüklemiş olmalısınız."
|
116
117
|
};
|
117
118
|
// ====================
|
118
119
|
// Stil Ayarları
|
@@ -130,7 +131,7 @@ var spinnerStyle = {
|
|
130
131
|
zIndex: 3,
|
131
132
|
};
|
132
133
|
var dropAreaStyle = {
|
133
|
-
border: "2px dashed #007bff",
|
134
|
+
//border: "2px dashed #007bff",
|
134
135
|
borderRadius: "5px",
|
135
136
|
padding: "20px",
|
136
137
|
textAlign: "center",
|
@@ -227,6 +228,7 @@ var CustomFileUploader = (0, react_1.forwardRef)(function (props, ref) {
|
|
227
228
|
var finalTranslations = __assign(__assign({}, exports.defaultTranslations), translations);
|
228
229
|
var _a = (0, react_1.useState)([]), previews = _a[0], setPreviews = _a[1];
|
229
230
|
var fileInputRef = (0, react_1.useRef)(null);
|
231
|
+
var isInvalid = props.required && props.submitted && !previews.some(function (p) { return p.uploaded; });
|
230
232
|
// Parent submit öncesi çağırıyor: pending varsa uyar ve blokla
|
231
233
|
(0, react_1.useImperativeHandle)(ref, function () { return ({
|
232
234
|
validateReady: function () {
|
@@ -235,9 +237,17 @@ var CustomFileUploader = (0, react_1.forwardRef)(function (props, ref) {
|
|
235
237
|
onNotify === null || onNotify === void 0 ? void 0 : onNotify.warning(finalTranslations.pendingBeforeSubmitWarning || exports.defaultTranslations.pendingBeforeSubmitWarning);
|
236
238
|
return false;
|
237
239
|
}
|
240
|
+
// REQUIRED kuralı: en az 1 adet YÜKLENMİŞ dosya olmalı
|
241
|
+
if (props.required) {
|
242
|
+
var hasUploaded = previews.some(function (p) { return p.uploaded; });
|
243
|
+
if (!hasUploaded) {
|
244
|
+
onNotify === null || onNotify === void 0 ? void 0 : onNotify.warning(finalTranslations.requiredBeforeSubmitWarning || exports.defaultTranslations.requiredBeforeSubmitWarning);
|
245
|
+
return false;
|
246
|
+
}
|
247
|
+
}
|
238
248
|
return true;
|
239
249
|
}
|
240
|
-
}); }, [previews, finalTranslations, onNotify]);
|
250
|
+
}); }, [previews, finalTranslations, onNotify, props.required]);
|
241
251
|
// CustomFileUploader.tsx içinde component’in üst kısmına, diğer handler’ların yanına ekleyin:
|
242
252
|
var handleClearAll = function () {
|
243
253
|
previews.forEach(function (item) {
|
@@ -433,7 +443,7 @@ var CustomFileUploader = (0, react_1.forwardRef)(function (props, ref) {
|
|
433
443
|
return (react_1.default.createElement("div", { style: { width: "100%", height: "100%" } },
|
434
444
|
label && (react_1.default.createElement("div", { style: { marginBottom: "10px" } },
|
435
445
|
react_1.default.createElement("label", { style: { fontWeight: "bold" } }, label))),
|
436
|
-
react_1.default.createElement("div", { style: dropAreaStyle, onDrop: handleDrop, onDragOver: handleDragOver, onClick: handleAreaClick }, previews.length === 0 ? (react_1.default.createElement("div", null, dropAreaText)) : (react_1.default.createElement("div", { style: previewContainerStyle }, previews.map(function (item) { return (react_1.default.createElement("div", { key: item.id, style: { display: "flex", flexDirection: "column", alignItems: "center" } },
|
446
|
+
react_1.default.createElement("div", { style: __assign(__assign({}, dropAreaStyle), { border: isInvalid ? "2px dashed #ff0000ff" : "2px dashed #007bff" }), onDrop: handleDrop, onDragOver: handleDragOver, onClick: handleAreaClick }, previews.length === 0 ? (react_1.default.createElement("div", null, dropAreaText)) : (react_1.default.createElement("div", { style: previewContainerStyle }, previews.map(function (item) { return (react_1.default.createElement("div", { key: item.id, style: { display: "flex", flexDirection: "column", alignItems: "center" } },
|
437
447
|
react_1.default.createElement("div", { style: previewItemStyle },
|
438
448
|
item.isUploading && react_1.default.createElement("div", { style: spinnerStyle }),
|
439
449
|
item.isImage ? (react_1.default.createElement("img", { src: item.previewContent, alt: "\u00D6nizleme ".concat(item.id), style: {
|
@@ -467,6 +477,9 @@ var CustomFileUploader = (0, react_1.forwardRef)(function (props, ref) {
|
|
467
477
|
react_1.default.createElement("input", { type: "file", multiple: multi, ref: fileInputRef, onChange: handleFileChange, style: { display: "none" } }),
|
468
478
|
react_1.default.createElement("div", { className: "d-flex justify-content-center gap-2 mt-3" },
|
469
479
|
previews.length > 1 && (react_1.default.createElement(CustomButton_1.default, { label: "T\u00FCm\u00FCn\u00FC Sil", className: "btn btn-danger", onClick: handleClearAll })),
|
470
|
-
previews.filter(function (item) { return !item.uploaded; }).length > 0 && (react_1.default.createElement(CustomButton_1.default, { label: finalTranslations.uploadButtonText, className: "btn btn-primary", onClick: handleUpload })))
|
480
|
+
previews.filter(function (item) { return !item.uploaded; }).length > 0 && (react_1.default.createElement(CustomButton_1.default, { label: finalTranslations.uploadButtonText, className: "btn btn-primary", onClick: handleUpload }))),
|
481
|
+
isInvalid && (react_1.default.createElement("div", { className: "invalid-feedback d-block text-danger mt-1" },
|
482
|
+
react_1.default.createElement(fa_1.FaExclamationTriangle, { className: "me-1" }),
|
483
|
+
finalTranslations.requiredBeforeSubmitWarning || "Bu alan boş bırakılamaz."))));
|
471
484
|
});
|
472
485
|
exports.default = CustomFileUploader;
|
@@ -200,6 +200,7 @@ interface FileUploaderElement {
|
|
200
200
|
allowedTypes: AllowedTypes;
|
201
201
|
maxFile: number;
|
202
202
|
maxSize: number;
|
203
|
+
required?: boolean;
|
203
204
|
onUploadComplete: (uploadedFileNames: string[]) => void;
|
204
205
|
onRemoveUploaded: (fileName: string) => void;
|
205
206
|
onPendingChange: (pendingFileCount: number) => void;
|
@@ -131,35 +131,32 @@ var CustomForm = function (_a) {
|
|
131
131
|
uploaderInstances.current[id] = inst;
|
132
132
|
}; };
|
133
133
|
var handleConfirm = function (e) { return __awaiter(void 0, void 0, void 0, function () {
|
134
|
-
var instances, _i, instances_1, inst, ok,
|
135
|
-
var
|
136
|
-
return __generator(this, function (
|
137
|
-
switch (
|
134
|
+
var form, uploaderValid, instances, _i, instances_1, inst, ok, customSelectValid, customTreeViewValid, nativeValid, allValid, formValues_1, _a;
|
135
|
+
var _b, _c;
|
136
|
+
return __generator(this, function (_d) {
|
137
|
+
switch (_d.label) {
|
138
138
|
case 0:
|
139
139
|
e.preventDefault();
|
140
|
-
|
140
|
+
// 1) Görsel validasyon state'lerini aç
|
141
|
+
setSubmitted(true);
|
142
|
+
form = formRef.current;
|
143
|
+
if (!form)
|
144
|
+
return [2 /*return*/];
|
145
|
+
uploaderValid = true;
|
141
146
|
instances = Object.values(uploaderInstances.current);
|
142
147
|
for (_i = 0, instances_1 = instances; _i < instances_1.length; _i++) {
|
143
148
|
inst = instances_1[_i];
|
144
|
-
ok = (
|
149
|
+
ok = (_b = inst === null || inst === void 0 ? void 0 : inst.validateReady) === null || _b === void 0 ? void 0 : _b.call(inst);
|
145
150
|
if (ok === false) {
|
146
|
-
|
147
|
-
return [2 /*return*/];
|
151
|
+
uploaderValid = false;
|
148
152
|
}
|
149
153
|
}
|
150
|
-
setSubmitted(true);
|
151
|
-
form = formRef.current;
|
152
|
-
if (!form)
|
153
|
-
return [2 /*return*/];
|
154
154
|
customSelectValid = true;
|
155
155
|
elements.forEach(function (element) {
|
156
|
-
if (element.type === ElementType.SELECT &&
|
157
|
-
element.required) {
|
156
|
+
if (element.type === ElementType.SELECT && element.required) {
|
158
157
|
var selectElement = element;
|
159
|
-
|
160
|
-
if ((Array.isArray(
|
161
|
-
selectElement.value.length === 0) ||
|
162
|
-
(!Array.isArray(selectElement.value) && !selectElement.value)) {
|
158
|
+
var val = selectElement.value;
|
159
|
+
if ((Array.isArray(val) && val.length === 0) || (!Array.isArray(val) && !val)) {
|
163
160
|
customSelectValid = false;
|
164
161
|
}
|
165
162
|
}
|
@@ -174,12 +171,22 @@ var CustomForm = function (_a) {
|
|
174
171
|
}
|
175
172
|
}
|
176
173
|
});
|
177
|
-
|
178
|
-
|
174
|
+
nativeValid = form.checkValidity();
|
175
|
+
allValid = uploaderValid && customSelectValid && customTreeViewValid && nativeValid;
|
176
|
+
if (!allValid) {
|
177
|
+
// Bootstrap görsel validasyonlarını hemen göster
|
178
|
+
form.classList.add("was-validated");
|
179
|
+
// Destekleyen tarayıcılarda nerenin hatalı olduğunu anında gösterir
|
180
|
+
(_c = form.reportValidity) === null || _c === void 0 ? void 0 : _c.call(form);
|
181
|
+
// Kullanıcıya genel mesaj
|
182
|
+
notify.error("Gerekli tüm alanları doldurunuz.");
|
183
|
+
return [2 /*return*/];
|
184
|
+
}
|
185
|
+
// 7) BURADAN SONRA GERÇEK SUBMIT
|
179
186
|
setIsLoading(true);
|
180
|
-
|
187
|
+
_d.label = 1;
|
181
188
|
case 1:
|
182
|
-
|
189
|
+
_d.trys.push([1, 3, 4, 5]);
|
183
190
|
formValues_1 = {};
|
184
191
|
Array.from(form.elements).forEach(function (element) {
|
185
192
|
if (element instanceof HTMLInputElement ||
|
@@ -187,18 +194,15 @@ var CustomForm = function (_a) {
|
|
187
194
|
element instanceof HTMLSelectElement) {
|
188
195
|
if (element.id) {
|
189
196
|
var name_1 = element.name || element.id;
|
190
|
-
if (element instanceof HTMLInputElement &&
|
191
|
-
element.type === ElementType.RADIO) {
|
197
|
+
if (element instanceof HTMLInputElement && element.type === "radio") {
|
192
198
|
if (element.checked) {
|
193
199
|
formValues_1[name_1] = element.value;
|
194
200
|
}
|
195
201
|
}
|
196
|
-
else if (element instanceof HTMLInputElement &&
|
197
|
-
element.type === ElementType.CHECKBOX) {
|
202
|
+
else if (element instanceof HTMLInputElement && element.type === "checkbox") {
|
198
203
|
formValues_1[name_1] = element.checked;
|
199
204
|
}
|
200
|
-
else if (element instanceof HTMLSelectElement &&
|
201
|
-
element.multiple) {
|
205
|
+
else if (element instanceof HTMLSelectElement && element.multiple) {
|
202
206
|
var selectedOptions = Array.from(element.selectedOptions).map(function (option) { return option.value; });
|
203
207
|
formValues_1[name_1] = selectedOptions;
|
204
208
|
}
|
@@ -211,7 +215,6 @@ var CustomForm = function (_a) {
|
|
211
215
|
}
|
212
216
|
}
|
213
217
|
});
|
214
|
-
// Özel elemanlar için (örneğin RichTextbox) değerleri ekleyin
|
215
218
|
elements.forEach(function (element) {
|
216
219
|
if ("value" in element && element.type === ElementType.RICHTEXTBOX) {
|
217
220
|
formValues_1[element.id] = element.value;
|
@@ -219,21 +222,16 @@ var CustomForm = function (_a) {
|
|
219
222
|
});
|
220
223
|
return [4 /*yield*/, onSubmit(formValues_1)];
|
221
224
|
case 2:
|
222
|
-
|
225
|
+
_d.sent();
|
223
226
|
return [3 /*break*/, 5];
|
224
227
|
case 3:
|
225
|
-
|
228
|
+
_a = _d.sent();
|
226
229
|
notify.error("Form gönderimi sırasında bir hata oluştu.");
|
227
230
|
return [3 /*break*/, 5];
|
228
231
|
case 4:
|
229
232
|
setIsLoading(false);
|
230
233
|
return [7 /*endfinally*/];
|
231
|
-
case 5: return [
|
232
|
-
case 6:
|
233
|
-
notify.error("Gerekli tüm alanları doldurunuz.");
|
234
|
-
form.classList.add("was-validated");
|
235
|
-
_b.label = 7;
|
236
|
-
case 7: return [2 /*return*/];
|
234
|
+
case 5: return [2 /*return*/];
|
237
235
|
}
|
238
236
|
});
|
239
237
|
}); };
|
@@ -265,7 +263,7 @@ var CustomForm = function (_a) {
|
|
265
263
|
} }))) : element.type === ElementType.DATETIMEPICKER ? (react_1.default.createElement(CustomDateTimePicker_1.default, __assign({}, element, { submitted: submitted }))) : element.type === ElementType.DIVIDER ? (react_1.default.createElement(CustomDivider_1.default, __assign({}, element))) : element.type === ElementType.RICHTEXTBOX ? (react_1.default.createElement(CustomRichTextbox_1.default, __assign({}, element))) : element.type === ElementType.TREEVIEW ? (react_1.default.createElement(CustomTreeView_1.default, __assign({}, element, { submitted: submitted }))) : element.type === ElementType.BUTTON ? (react_1.default.createElement(CustomButton_1.default, __assign({}, element, { isLoading: isLoading }))) : element.type === ElementType.AUTOCOMPLETEINPUT ? (react_1.default.createElement(CustomAutocompleteInput_1.default, __assign({}, element))) : element.type === ElementType.PHONE ? (react_1.default.createElement(CustomPhoneInput_1.default, __assign({}, element))) : element.type === ElementType.FILEUPLOADER ? (
|
266
264
|
// FILEUPLOADER elemanı için CustomFileUploader'ı render ediyoruz
|
267
265
|
react_1.default.createElement(react_1.default.Fragment, null,
|
268
|
-
react_1.default.createElement(CustomFileUploader_1.default, { ref: getUploaderRefCb(element.id), url: element.url, multi: element.multi, allowedTypes: element.allowedTypes, maxFile: element.maxFile, maxSize: element.maxSize, onUploadComplete: element.onUploadComplete, onRemoveUploaded: element.onRemoveUploaded, onPendingChange: element.onPendingChange, clearTrigger: element.clearTrigger, label: element.label, translations: element.translations, onUploadingChange: setIsUploading, onNotify: onNotify }))) : null)); })));
|
266
|
+
react_1.default.createElement(CustomFileUploader_1.default, { ref: getUploaderRefCb(element.id), url: element.url, multi: element.multi, allowedTypes: element.allowedTypes, maxFile: element.maxFile, maxSize: element.maxSize, required: element.required, submitted: submitted, onUploadComplete: element.onUploadComplete, onRemoveUploaded: element.onRemoveUploaded, onPendingChange: element.onPendingChange, clearTrigger: element.clearTrigger, label: element.label, translations: element.translations, onUploadingChange: setIsUploading, onNotify: onNotify }))) : null)); })));
|
269
267
|
})));
|
270
268
|
})));
|
271
269
|
}),
|