first commit
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
// File: add_edit_variation.dart
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mobile_pos/Screens/product%20variation/repo/product_variation_repo.dart';
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as l;
|
||||
import 'model/product_variation_model.dart';
|
||||
|
||||
class AddEditVariation extends ConsumerStatefulWidget {
|
||||
final bool isEdit;
|
||||
final VariationData? variation;
|
||||
|
||||
const AddEditVariation({super.key, this.isEdit = false, this.variation});
|
||||
|
||||
@override
|
||||
ConsumerState<AddEditVariation> createState() => _AddEditVariationState();
|
||||
}
|
||||
|
||||
class _AddEditVariationState extends ConsumerState<AddEditVariation> {
|
||||
final GlobalKey<FormState> _key = GlobalKey<FormState>();
|
||||
final TextEditingController nameController = TextEditingController();
|
||||
final TextEditingController valueInputController = TextEditingController(); // Input for adding new tag
|
||||
|
||||
List<String> _selectedValues = []; // List of values (tags)
|
||||
String? _selectedStatus;
|
||||
|
||||
final List<String> _statusOptions = ['Active', 'Inactive'];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.isEdit && widget.variation != null) {
|
||||
final data = widget.variation!;
|
||||
nameController.text = data.name ?? '';
|
||||
|
||||
// Load initial status
|
||||
_selectedStatus = (data.status == 1) ? 'Active' : 'Inactive';
|
||||
|
||||
// Load existing values (List<String>)
|
||||
_selectedValues = data.values ?? [];
|
||||
} else {
|
||||
_selectedStatus = 'Active';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
valueInputController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// --- Tag/Chip Management ---
|
||||
void _addValue(String value) {
|
||||
final trimmed = value.trim();
|
||||
if (trimmed.isNotEmpty && !_selectedValues.contains(trimmed)) {
|
||||
setState(() {
|
||||
_selectedValues.add(trimmed);
|
||||
});
|
||||
valueInputController.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void _removeValue(String value) {
|
||||
setState(() {
|
||||
_selectedValues.remove(value);
|
||||
});
|
||||
_key.currentState?.validate();
|
||||
}
|
||||
|
||||
// --- Submission Logic ---
|
||||
Future<void> _submit() async {
|
||||
if (!_key.currentState!.validate()) return;
|
||||
|
||||
// Final check for values input (if user entered text but didn't press enter/add)
|
||||
_addValue(valueInputController.text);
|
||||
|
||||
if (_selectedValues.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Please enter at least one value.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final repo = VariationRepo();
|
||||
final String apiStatus = _selectedStatus == 'Active' ? '1' : '0';
|
||||
|
||||
// CRITICAL: Convert List<String> to Comma Separated String for API payload
|
||||
final String valuesString = _selectedValues.join(',');
|
||||
|
||||
if (widget.isEdit) {
|
||||
await repo.updateVariation(
|
||||
ref: ref,
|
||||
context: context,
|
||||
id: widget.variation!.id!.round(),
|
||||
name: nameController.text,
|
||||
values: valuesString,
|
||||
status: apiStatus,
|
||||
);
|
||||
} else {
|
||||
await repo.createVariation(
|
||||
ref: ref,
|
||||
context: context,
|
||||
name: nameController.text,
|
||||
values: valuesString,
|
||||
status: apiStatus,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Reset Logic ---
|
||||
void _resetForm() {
|
||||
if (widget.isEdit) {
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
setState(() {
|
||||
_key.currentState?.reset();
|
||||
nameController.clear();
|
||||
valueInputController.clear();
|
||||
_selectedStatus = 'Active';
|
||||
_selectedValues = [];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Helper widget to display values as chips
|
||||
Widget _buildValueChip(String value) {
|
||||
return Chip(
|
||||
label: Text(value),
|
||||
backgroundColor: kMainColor.withOpacity(0.1),
|
||||
labelStyle: const TextStyle(color: kMainColor),
|
||||
deleteIcon: const Icon(Icons.close, size: 16),
|
||||
onDeleted: () => _removeValue(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _lang = l.S.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(widget.isEdit ? _lang.editVariations : _lang.addNewVariation),
|
||||
actions: [IconButton(onPressed: () => Navigator.pop(context), icon: const Icon(Icons.close))],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Form(
|
||||
key: _key,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 1. Variation Name Input
|
||||
TextFormField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(labelText: _lang.name, hintText: _lang.enterName),
|
||||
validator: (value) => value!.isEmpty ? _lang.pleaseEnterName : null,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 2. Values (Chip/Tag Input)
|
||||
Text(_lang.values, style: Theme.of(context).textTheme.bodyLarge),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
Container(
|
||||
width: 500,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey.shade400),
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 4.0,
|
||||
children: [
|
||||
..._selectedValues.map(_buildValueChip),
|
||||
IntrinsicWidth(
|
||||
child: TextField(
|
||||
controller: valueInputController,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
hintText: _lang.enterValues,
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 0),
|
||||
),
|
||||
|
||||
// Input settings
|
||||
// CRITICAL FIX: Use onSubmitted to handle 'Enter' key press
|
||||
onSubmitted: (value) => _addValue(value),
|
||||
|
||||
// onEditingComplete is also useful but usually triggered by software keyboard's 'Done'
|
||||
onEditingComplete: () => _addValue(valueInputController.text),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Hidden Validator based on selected list
|
||||
if (_selectedValues.isEmpty && valueInputController.text.isEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
_lang.pleaseEnterAtLeastOneValues,
|
||||
style: TextStyle(color: Colors.red.shade700, fontSize: 12),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 3. Status Dropdown
|
||||
DropdownButtonFormField<String>(
|
||||
value: _selectedStatus,
|
||||
icon: const Icon(Icons.keyboard_arrow_down, color: kNeutral800),
|
||||
decoration: InputDecoration(labelText: _lang.status, hintText: _lang.selectOne),
|
||||
items: [
|
||||
DropdownMenuItem(value: 'Active', child: Text(_lang.active)),
|
||||
DropdownMenuItem(value: 'Inactive', child: Text(_lang.inactive)),
|
||||
],
|
||||
// items:
|
||||
// _statusOptions.map((String value) => DropdownMenuItem(value: value, child: Text(value))).toList(),
|
||||
onChanged: (String? newValue) => setState(() => _selectedStatus = newValue),
|
||||
validator: (value) => value == null ? _lang.pleaseSelectAStatus : null,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// 4. Action Buttons (Reset/Save)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: _resetForm,
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(double.infinity, 50),
|
||||
side: const BorderSide(color: Colors.red),
|
||||
foregroundColor: Colors.red,
|
||||
),
|
||||
child: Text(_lang.resets),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: _submit,
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: const Size(double.infinity, 50),
|
||||
backgroundColor: const Color(0xFFB71C1C),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: Text(widget.isEdit ? _lang.update : _lang.save),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
class VariationListModel {
|
||||
VariationListModel({
|
||||
this.message,
|
||||
this.data,
|
||||
});
|
||||
|
||||
VariationListModel.fromJson(dynamic json) {
|
||||
message = json['message'];
|
||||
if (json['data'] != null) {
|
||||
data = [];
|
||||
json['data'].forEach((v) {
|
||||
data?.add(VariationData.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
String? message;
|
||||
List<VariationData>? data;
|
||||
}
|
||||
|
||||
class VariationData {
|
||||
VariationData({
|
||||
this.id,
|
||||
this.name,
|
||||
this.status,
|
||||
this.values,
|
||||
});
|
||||
|
||||
VariationData.fromJson(dynamic json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
status = json['status'];
|
||||
|
||||
if (json['values'] is List) {
|
||||
values = List<String>.from(json['values']);
|
||||
}
|
||||
}
|
||||
num? id;
|
||||
String? name;
|
||||
num? status; // 1 or 0
|
||||
List<String>? values;
|
||||
}
|
||||
228
lib/Screens/product variation/product_variation_list_screen.dart
Normal file
228
lib/Screens/product variation/product_variation_list_screen.dart
Normal file
@@ -0,0 +1,228 @@
|
||||
// File: product_variation_list.dart
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mobile_pos/Screens/product%20variation/provider/product_variation_provider.dart';
|
||||
import 'package:mobile_pos/Screens/product%20variation/repo/product_variation_repo.dart';
|
||||
|
||||
// --- Local Imports ---
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:mobile_pos/Screens/hrm/widgets/model_bottom_sheet.dart';
|
||||
import '../../../service/check_user_role_permission_provider.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
|
||||
// --- Data Layer Imports ---
|
||||
import '../hrm/widgets/deleteing_alart_dialog.dart';
|
||||
import '../hrm/widgets/global_search_appbar.dart';
|
||||
import '../product_category/product_category_list_screen.dart';
|
||||
import 'add_edit_product_variation_screen.dart';
|
||||
import 'model/product_variation_model.dart';
|
||||
|
||||
class ProductVariationList extends ConsumerStatefulWidget {
|
||||
const ProductVariationList({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<ProductVariationList> createState() => _ProductVariationListState();
|
||||
}
|
||||
|
||||
class _ProductVariationListState extends ConsumerState<ProductVariationList> {
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
List<VariationData> _filteredList = [];
|
||||
bool _isSearch = false;
|
||||
String search = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_searchController.addListener(_onSearchChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.removeListener(_onSearchChanged);
|
||||
_searchController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onSearchChanged() {
|
||||
setState(() {
|
||||
search = _searchController.text;
|
||||
});
|
||||
}
|
||||
|
||||
void _filterVariations(List<VariationData> allVariations) {
|
||||
final query = search.toLowerCase().trim();
|
||||
if (query.isEmpty) {
|
||||
_filteredList = allVariations;
|
||||
} else {
|
||||
_filteredList = allVariations.where((variation) {
|
||||
final nameMatch = (variation.name ?? '').toLowerCase().contains(query);
|
||||
final valuesMatch = (variation.values ?? []).join(', ').toLowerCase().contains(query);
|
||||
|
||||
return nameMatch || valuesMatch;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
String _getStatusText(dynamic status) {
|
||||
if (status == 1 || status == '1') return 'Active';
|
||||
return 'Inactive';
|
||||
}
|
||||
|
||||
Color _getStatusColor(dynamic status) {
|
||||
if (status == 1 || status == '1') return kSuccessColor;
|
||||
return Colors.red;
|
||||
}
|
||||
|
||||
Future<void> _refreshData() async {
|
||||
ref.invalidate(variationListProvider);
|
||||
return ref.watch(variationListProvider.future);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _lang = lang.S.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final variationListAsync = ref.watch(variationListProvider);
|
||||
final permissionService = PermissionService(ref);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: GlobalSearchAppBar(
|
||||
isSearch: _isSearch,
|
||||
onSearchToggle: () {
|
||||
setState(() {
|
||||
_isSearch = !_isSearch;
|
||||
if (!_isSearch) {
|
||||
_searchController.clear();
|
||||
}
|
||||
});
|
||||
},
|
||||
title: _lang.productVariations,
|
||||
controller: _searchController,
|
||||
onChanged: (query) {
|
||||
// Handled by _searchController.addListener
|
||||
},
|
||||
),
|
||||
body: variationListAsync.when(
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (err, stack) => Center(child: Text('Failed to load variations: $err')),
|
||||
data: (model) {
|
||||
// NOTE: Replace 'variation_read_permit' with your actual Permit.value
|
||||
if (!permissionService.hasPermission('variation_read_permit')) {
|
||||
// return const Center(child: PermitDenyWidget()); // Assuming this exists
|
||||
return Center(child: Text(_lang.permissionDenied));
|
||||
}
|
||||
final allVariations = model.data ?? [];
|
||||
|
||||
_filterVariations(allVariations);
|
||||
|
||||
if (_filteredList.isEmpty) {
|
||||
return Center(
|
||||
child: Text(search.isEmpty ? _lang.noVariationFound : _lang.notMatchingResultFound,
|
||||
style: theme.textTheme.titleMedium));
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: _refreshData,
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: _filteredList.length,
|
||||
separatorBuilder: (_, __) => const Divider(color: kBackgroundColor, height: 1.5),
|
||||
itemBuilder: (_, index) => _buildVariationItem(context, ref, _filteredList[index]),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
bottomNavigationBar: permissionService.hasPermission('variation_create_permit')
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () =>
|
||||
Navigator.push(context, MaterialPageRoute(builder: (context) => const AddEditVariation())),
|
||||
icon: const Icon(Icons.add, color: Colors.white),
|
||||
label: Text(_lang.addNewVariation),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
// --- Helper Methods ---
|
||||
|
||||
Widget _buildVariationItem(BuildContext context, WidgetRef ref, VariationData variation) {
|
||||
final permissionService = PermissionService(ref);
|
||||
final theme = Theme.of(context);
|
||||
final statusText = _getStatusText(variation.status);
|
||||
final statusColor = _getStatusColor(variation.status);
|
||||
final valuesText = (variation.values ?? []).join(', ');
|
||||
|
||||
return ListCardWidget(
|
||||
// Assuming ListCardWidget is available
|
||||
onSelect: () => viewModalSheet(
|
||||
context: context,
|
||||
item: {
|
||||
lang.S.of(context).name: variation.name ?? 'N/A',
|
||||
lang.S.of(context).status: statusText,
|
||||
lang.S.of(context).values: valuesText,
|
||||
},
|
||||
description: '${lang.S.of(context).variationId}: ${variation.id ?? 'N/A'}',
|
||||
),
|
||||
|
||||
title: variation.name ?? 'N/A ${lang.S.of(context).variations}',
|
||||
subtitle: valuesText.isEmpty ? lang.S.of(context).noValuesDenied : valuesText,
|
||||
onEdit: () {
|
||||
if (!permissionService.hasPermission('variation_update_permit')) return;
|
||||
Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) => AddEditVariation(isEdit: true, variation: variation)));
|
||||
},
|
||||
onDelete: () {
|
||||
if (!permissionService.hasPermission('variation_delete_permit')) return;
|
||||
if (variation.id != null) {
|
||||
_showDeleteConfirmationDialog(context, ref, variation.id!);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButtons(BuildContext context, WidgetRef ref, VariationData variation) {
|
||||
final permissionService = PermissionService(ref);
|
||||
return PopupMenuButton<String>(
|
||||
onSelected: (value) {
|
||||
if (value == 'edit') {
|
||||
if (!permissionService.hasPermission('variation_update_permit')) return;
|
||||
Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) => AddEditVariation(isEdit: true, variation: variation)));
|
||||
} else if (value == 'delete') {
|
||||
if (!permissionService.hasPermission('variation_delete_permit')) return;
|
||||
if (variation.id != null) {
|
||||
_showDeleteConfirmationDialog(context, ref, variation.id!);
|
||||
}
|
||||
}
|
||||
},
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||
PopupMenuItem<String>(
|
||||
value: 'edit',
|
||||
child: Text(lang.S.of(context).edit, style: TextStyle(color: kSuccessColor)),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'delete',
|
||||
child: Text(lang.S.of(context).delete, style: TextStyle(color: Colors.red)),
|
||||
),
|
||||
],
|
||||
icon: const Icon(Icons.more_vert),
|
||||
);
|
||||
}
|
||||
|
||||
void _showDeleteConfirmationDialog(BuildContext context, WidgetRef ref, num id) async {
|
||||
bool result = await showDeleteConfirmationDialog(
|
||||
context: context,
|
||||
itemName: lang.S.of(context).variations,
|
||||
);
|
||||
|
||||
if (result) {
|
||||
final repo = VariationRepo();
|
||||
await repo.deleteVariation(id: id, context: context, ref: ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../model/product_variation_model.dart';
|
||||
import '../repo/product_variation_repo.dart';
|
||||
|
||||
final repo = VariationRepo();
|
||||
final variationListProvider = FutureProvider<VariationListModel>((ref) => repo.fetchAllVariations());
|
||||
166
lib/Screens/product variation/repo/product_variation_repo.dart
Normal file
166
lib/Screens/product variation/repo/product_variation_repo.dart
Normal file
@@ -0,0 +1,166 @@
|
||||
// File: variation_repo.dart
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
// --- Local Imports ---
|
||||
import '../../../../Const/api_config.dart';
|
||||
import '../../../../http_client/custome_http_client.dart';
|
||||
import '../../../http_client/customer_http_client_get.dart';
|
||||
import '../model/product_variation_model.dart';
|
||||
import '../provider/product_variation_provider.dart';
|
||||
|
||||
class VariationRepo {
|
||||
static const String _endpoint = '/variations';
|
||||
|
||||
///---------------- FETCH ALL VARIATIONS (GET) ----------------///
|
||||
Future<VariationListModel> fetchAllVariations() async {
|
||||
CustomHttpClientGet clientGet = CustomHttpClientGet(client: http.Client());
|
||||
final uri = Uri.parse('${APIConfig.url}$_endpoint');
|
||||
|
||||
final response = await clientGet.get(url: uri);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final parsedData = jsonDecode(response.body);
|
||||
return VariationListModel.fromJson(parsedData);
|
||||
} else {
|
||||
throw Exception('Failed to fetch variation list. Status: ${response.statusCode}');
|
||||
}
|
||||
}
|
||||
|
||||
///---------------- CREATE VARIATION (POST) ----------------///
|
||||
Future<void> createVariation({
|
||||
required WidgetRef ref,
|
||||
required BuildContext context,
|
||||
required String name,
|
||||
required String values, // Comma separated string of values
|
||||
required String status, // "1" or "0"
|
||||
}) async {
|
||||
final uri = Uri.parse('${APIConfig.url}$_endpoint');
|
||||
|
||||
final requestBody = jsonEncode({
|
||||
'name': name,
|
||||
'values': values,
|
||||
'status': status,
|
||||
});
|
||||
|
||||
CustomHttpClient customHttpClient = CustomHttpClient(client: http.Client(), context: context, ref: ref);
|
||||
|
||||
try {
|
||||
EasyLoading.show(status: 'Creating Variation...');
|
||||
var responseData = await customHttpClient.post(
|
||||
url: uri,
|
||||
addContentTypeInHeader: true,
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
final parsedData = jsonDecode(responseData.body);
|
||||
EasyLoading.dismiss();
|
||||
|
||||
if (responseData.statusCode == 200 || responseData.statusCode == 201) {
|
||||
ref.invalidate(variationListProvider);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(parsedData['message'] ?? 'Variation created successfully')),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Creation failed: ${parsedData['message'] ?? 'Unknown error'}')),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
EasyLoading.dismiss();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('An error occurred: $error')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
///---------------- UPDATE VARIATION (PUT) ----------------///
|
||||
Future<void> updateVariation({
|
||||
required WidgetRef ref,
|
||||
required BuildContext context,
|
||||
required num id,
|
||||
required String name,
|
||||
required String values,
|
||||
required String status,
|
||||
}) async {
|
||||
final uri = Uri.parse('${APIConfig.url}$_endpoint/$id');
|
||||
|
||||
final requestBody = jsonEncode({
|
||||
'_method': 'put', // Use POST method with _method=put
|
||||
'name': name,
|
||||
'values': values,
|
||||
'status': status,
|
||||
});
|
||||
|
||||
CustomHttpClient customHttpClient = CustomHttpClient(client: http.Client(), context: context, ref: ref);
|
||||
|
||||
try {
|
||||
EasyLoading.show(status: 'Updating Variation...');
|
||||
var responseData = await customHttpClient.post(
|
||||
url: uri,
|
||||
addContentTypeInHeader: true,
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
final parsedData = jsonDecode(responseData.body);
|
||||
EasyLoading.dismiss();
|
||||
|
||||
if (responseData.statusCode == 200) {
|
||||
ref.invalidate(variationListProvider);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(parsedData['message'] ?? 'Variation updated successfully')),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Update failed: ${parsedData['message'] ?? 'Unknown error'}')),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
EasyLoading.dismiss();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('An error occurred: $error')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
///---------------- DELETE VARIATION ----------------///
|
||||
Future<bool> deleteVariation({
|
||||
required num id,
|
||||
required BuildContext context,
|
||||
required WidgetRef ref,
|
||||
}) async {
|
||||
try {
|
||||
EasyLoading.show(status: 'Deleting...');
|
||||
final url = Uri.parse('${APIConfig.url}$_endpoint/$id');
|
||||
CustomHttpClient customHttpClient = CustomHttpClient(ref: ref, context: context, client: http.Client());
|
||||
final response = await customHttpClient.delete(url: url);
|
||||
|
||||
EasyLoading.dismiss();
|
||||
if (response.statusCode == 200) {
|
||||
ref.invalidate(variationListProvider);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Variation deleted successfully')),
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
final parsedData = jsonDecode(response.body);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Deletion failed: ${parsedData['message'] ?? 'Unknown error'}')),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
EasyLoading.dismiss();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('An error occurred during deletion: $error')),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user