diff --git a/src/components/admin/configuration-card/configuration-card.component.html b/src/components/admin/configuration-card/configuration-card.component.html
new file mode 100644
index 0000000..4424b41
--- /dev/null
+++ b/src/components/admin/configuration-card/configuration-card.component.html
@@ -0,0 +1,17 @@
+
+
+ {{ title }}
+
+
+
+
+
+ @if (isLoading) {
+
+ } @else {
+
+ }
+
+
diff --git a/src/components/admin/configuration-card/configuration-card.component.ts b/src/components/admin/configuration-card/configuration-card.component.ts
new file mode 100644
index 0000000..d5a637c
--- /dev/null
+++ b/src/components/admin/configuration-card/configuration-card.component.ts
@@ -0,0 +1,37 @@
+import {Component, EventEmitter, Input, Output} from '@angular/core';
+import {MatCardModule} from "@angular/material/card";
+import {MatButton} from "@angular/material/button";
+import {catchError, Observable, tap} from "rxjs";
+import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
+
+@Component({
+ selector: 'app-configuration-card',
+ imports: [
+ MatCardModule,
+ MatButton,
+ DataSpinnerComponent
+ ],
+ templateUrl: './configuration-card.component.html'
+})
+export class ConfigurationCardComponent {
+ @Input() title: string = '';
+ @Input() isSaveEnabled: boolean = false;
+ @Input() saveFunction!: () => Observable;
+ @Output() onSaveFunction = new EventEmitter();
+
+ protected isLoading: boolean = false;
+
+ onSave(): void {
+ this.isLoading = true;
+
+ const result = this.saveFunction().pipe(catchError(err => {
+ this.isLoading = false;
+ throw err;
+ }),
+ tap(_ => {
+ this.isLoading = false;
+ }));
+
+ this.onSaveFunction.emit(result);
+ }
+}