-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added issue screen * added issues tab bar and issue list * updated issuesList * navigate create issue screen * added dropdown component * after change value, give changed item * fixed post request * Checked validation * fix id * checked update and set value * After adding data, list is updated * added delete function * added confirm, toast * checked edit * fixed ui * fix data * fix category, type * fixed did not appeared value * fixed validation
- Loading branch information
Showing
10 changed files
with
492 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import React, { createRef, useState, useEffect } from 'react'; | ||
import { ScrollView, Text, TouchableOpacity, View } from 'react-native'; | ||
import ActionSheet from 'react-native-actions-sheet'; | ||
import { faAngleDown, faTimes } from '@fortawesome/free-solid-svg-icons'; | ||
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; | ||
import { useNavigation } from '@react-navigation/native'; | ||
import tailwind from 'tailwind'; | ||
|
||
import { getColorCode } from 'utils'; | ||
|
||
const DropdownActionSheet = ({ items, onChange, title, value }) => { | ||
const actionSheetRef = createRef(); | ||
const navigation = useNavigation(); | ||
const [selectedItem, setSelectedItem] = useState(null); | ||
|
||
useEffect(() => { | ||
const selected = items.find(item => item.value === value); | ||
if (selected) { | ||
setSelectedItem(selected); | ||
} | ||
}, [value]); | ||
|
||
const handleItemSelection = item => { | ||
setSelectedItem(item); | ||
onChange(item.value); | ||
actionSheetRef.current?.hide(); | ||
}; | ||
|
||
return ( | ||
<View style={tailwind('mb-4')}> | ||
<TouchableOpacity onPress={() => actionSheetRef.current?.setModalVisible()}> | ||
<View style={tailwind('flex flex-row items-center justify-between pb-1 bg-gray-900 border border-gray-700 rounded-lg px-2')}> | ||
<View style={tailwind('border-blue-700 py-2 pr-4 flex flex-row items-center')}> | ||
<Text style={[tailwind('font-semibold text-blue-50 text-base'), selectedItem && tailwind('px-2')]}>{selectedItem ? selectedItem.label : title}</Text> | ||
</View> | ||
<View style={tailwind('flex flex-row items-center')}>{<FontAwesomeIcon icon={faAngleDown} style={tailwind('text-white')} />}</View> | ||
</View> | ||
</TouchableOpacity> | ||
<ActionSheet | ||
gestureEnabled={true} | ||
bounceOnOpen={true} | ||
nestedScrollEnabled={true} | ||
onMomentumScrollEnd={() => actionSheetRef.current?.handleChildScrollEnd()} | ||
ref={actionSheetRef} | ||
containerStyle={tailwind('bg-gray-800')} | ||
indicatorColor={getColorCode('text-gray-900')}> | ||
<View> | ||
<View style={tailwind('px-5 py-2 flex flex-row items-center justify-between mb-2')}> | ||
<View style={tailwind('flex flex-row items-center')}> | ||
<Text style={tailwind('text-lg text-white font-semibold')}>{selectedItem ? selectedItem.label : title}</Text> | ||
</View> | ||
<View> | ||
<TouchableOpacity onPress={() => actionSheetRef.current?.hide()}> | ||
<View style={tailwind('rounded-full bg-red-700 w-8 h-8 flex items-center justify-center')}> | ||
<FontAwesomeIcon icon={faTimes} style={tailwind('text-red-100')} /> | ||
</View> | ||
</TouchableOpacity> | ||
</View> | ||
</View> | ||
<ScrollView showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false}> | ||
{items?.map(item => ( | ||
<TouchableOpacity key={item.value} onPress={() => handleItemSelection(item)}> | ||
<View style={tailwind('flex flex-row items-center px-5 py-4 border-b border-gray-900')}> | ||
<Text style={tailwind('font-semibold text-lg text-gray-100')}>{item.label}</Text> | ||
</View> | ||
</TouchableOpacity> | ||
))} | ||
<View style={tailwind('w-full h-40')}></View> | ||
</ScrollView> | ||
</View> | ||
</ActionSheet> | ||
</View> | ||
); | ||
}; | ||
|
||
export default DropdownActionSheet; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
const IssueType = { | ||
VEHICLE: 'Vehicle', | ||
DRIVER: 'Driver', | ||
ROUTE: 'Route', | ||
PAYLOAD_CARGO: 'Payload Cargo', | ||
SOFTWARE_TECHNICAL: 'Software Technical', | ||
OPERATIONAL: 'Operational', | ||
CUSTOMER: 'Customer', | ||
SECURITY: 'Security', | ||
ENVIRONMENTAL_SUSTAINABILITY: 'Environmental Sustainability', | ||
}; | ||
const IssueCategory = { | ||
Compliance: 'Compliance', | ||
ResourceAllocation: 'Resource Allocation', | ||
CostOverruns: 'Cost Overruns', | ||
Communication: 'Communication', | ||
VendorManagementIssue: 'Vendor Management Issue', | ||
}; | ||
|
||
const IssuePriority = { | ||
LOW: 'Low', | ||
MEDIUM: 'Medium', | ||
HIGH: 'High', | ||
CRITICAL: 'Critical', | ||
SCHEDULED_MAINTENANCE: 'Scheduled Maintenance', | ||
OPERATIONAL_SUGGESTION: 'Operational Suggestion', | ||
}; | ||
export { IssuePriority, IssueType, IssueCategory }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
export default function getIssueCategories(type = null, options) { | ||
const issueCategories = { | ||
VEHICLE: ['Mechanical Problems', 'Cosmetic Damages', 'Tire Issues', 'Electronics and Instruments', 'Maintenance Alerts', 'Fuel Efficiency Issues'], | ||
DRIVER: ['Behavior Concerns', 'Documentation', 'Time Management', 'Communication', 'Training Needs', 'Health and Safety Violations'], | ||
ROUTE: ['Inefficient Routes', 'Safety Concerns', 'Blocked Routes', 'Environmental Considerations', 'Unfavorable Weather Conditions'], | ||
PAYLOAD_CARGO: ['Damaged Goods', 'Misplaced Goods', 'Documentation Issues', 'Temperature-Sensitive Goods', 'Incorrect Cargo Loading'], | ||
SOFTWARE_TECHNICAL: ['Bugs', 'UI/UX Concerns', 'Integration Failures', 'Performance', 'Feature Requests', 'Security Vulnerabilities'], | ||
OPERATIONAL: ['Compliance', 'Resource Allocation', 'Cost Overruns', 'Communication', 'Vendor Management Issues'], | ||
CUSTOMER: ['Service Quality', 'Billing Discrepancies', 'Communication Breakdown', 'Feedback and Suggestions', 'Order Errors'], | ||
SECURITY: ['Unauthorized Access', 'Data Concerns', 'Physical Security', 'Data Integrity Issues'], | ||
ENVIRONMENTAL_SUSTAINABILITY: ['Fuel Consumption', 'Carbon Footprint', 'Waste Management', 'Green Initiatives Opportunities'], | ||
}; | ||
|
||
if (type) { | ||
return issueCategories[type] || []; | ||
} | ||
|
||
const allIssueCategories = Object.values(issueCategories).flat(); | ||
return allIssueCategories; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
import { faTimes } from '@fortawesome/free-solid-svg-icons'; | ||
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; | ||
import { IssuePriority, IssueType } from 'constant/Enum'; | ||
import { useDriver, useFleetbase } from 'hooks'; | ||
import React, { useEffect, useState } from 'react'; | ||
import { ActivityIndicator, Alert, Keyboard, KeyboardAvoidingView, Pressable, Text, TextInput, TouchableOpacity, View } from 'react-native'; | ||
import Toast from 'react-native-toast-message'; | ||
import tailwind from 'tailwind'; | ||
import { getColorCode, getCurrentLocation, logError, translate } from 'utils'; | ||
import DropdownActionSheet from '../../../components/DropdownActionSheet'; | ||
import getIssueCategories from '../../../constant/GetIssueCategoy'; | ||
|
||
const IssueScreen = ({ navigation, route }) => { | ||
const issue = route.params; | ||
const isEdit = route.params; | ||
const [isLoading, setIsLoading] = useState(false); | ||
const fleetbase = useFleetbase(); | ||
const [driver] = useDriver(); | ||
const [driverId] = useState(driver.getAttribute('id')); | ||
|
||
const [type, setType] = useState(issue.type); | ||
const [categories, setCategories] = useState([]); | ||
const [category, setCategory] = useState(); | ||
const [priority, setPriority] = useState(); | ||
const [report, setReport] = useState(issue.report); | ||
const [error, setError] = useState(''); | ||
|
||
useEffect(() => { | ||
if (issue) { | ||
setCategory(issue.issue?.category); | ||
setPriority(issue.issue?.priority); | ||
setReport(issue.issue?.report); | ||
setType(issue.issue?.type); | ||
} | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (!type) return; | ||
|
||
setCategories(getIssueCategories(type)); | ||
}, [type]); | ||
|
||
const saveIssue = () => { | ||
if (!validateInputs()) { | ||
return; | ||
} | ||
setIsLoading(true); | ||
const location = getCurrentLocation().then(); | ||
const adapter = fleetbase.getAdapter(); | ||
|
||
if (issue.issue?.id) { | ||
adapter | ||
.put(`issues/${issue.issue.id}`, { | ||
type, | ||
category, | ||
priority, | ||
report, | ||
location: location, | ||
driver: driverId, | ||
}) | ||
.then(() => { | ||
Toast.show({ | ||
type: 'success', | ||
text1: `Successfully updated`, | ||
}); | ||
setIsLoading(false); | ||
navigation.goBack(); | ||
}) | ||
.catch(error => { | ||
setIsLoading(false); | ||
logError(error); | ||
}); | ||
} else { | ||
adapter | ||
.post('issues', { | ||
type, | ||
category, | ||
priority, | ||
report, | ||
location: location, | ||
driver: driverId, | ||
}) | ||
.then(() => { | ||
Toast.show({ | ||
type: 'success', | ||
text1: `Successfully created`, | ||
}); | ||
setIsLoading(false); | ||
navigation.goBack(); | ||
}) | ||
.catch(error => { | ||
setIsLoading(false); | ||
logError(error); | ||
}); | ||
} | ||
}; | ||
|
||
const deleteIssues = () => { | ||
Alert.alert('Confirmation', 'Are you sure you want to delete this issue?', [ | ||
{ | ||
text: 'Cancel', | ||
style: 'cancel', | ||
}, | ||
{ | ||
text: 'Delete', | ||
onPress: () => confirmDelete(), | ||
}, | ||
]); | ||
}; | ||
|
||
const confirmDelete = () => { | ||
const adapter = fleetbase.getAdapter(); | ||
adapter | ||
.delete(`issues/${issue.issue.id}`) | ||
.then(() => { | ||
Toast.show({ | ||
type: 'success', | ||
text1: `Successfully deleted`, | ||
}); | ||
setIsLoading(false); | ||
navigation.goBack(); | ||
}) | ||
.catch(error => { | ||
setIsLoading(false); | ||
logError(error); | ||
}); | ||
}; | ||
|
||
const validateInputs = () => { | ||
if (!type || !category || !priority || !report?.trim()) { | ||
setError('Please enter a required value.'); | ||
return false; | ||
} else if (report.trim().length === 0) { | ||
setError('Report cannot be empty.'); | ||
return false; | ||
} | ||
setError(''); | ||
return true; | ||
}; | ||
|
||
return ( | ||
<View style={[tailwind('w-full h-full bg-gray-800')]}> | ||
<Pressable onPress={Keyboard.dismiss} style={tailwind('w-full h-full relative')}> | ||
<View style={tailwind('flex flex-row items-center justify-between p-4')}> | ||
{issue.isEdit ? ( | ||
<Text style={tailwind('text-xl text-gray-50 font-semibold')}>{translate('Core.IssueScreen.update')}</Text> | ||
) : ( | ||
<Text style={tailwind('text-xl text-gray-50 font-semibold')}>{translate('Core.IssueScreen.create')}</Text> | ||
)} | ||
<TouchableOpacity onPress={() => navigation.goBack()} style={tailwind('mr-4')}> | ||
<View style={tailwind('rounded-full bg-gray-900 w-10 h-10 flex items-center justify-center')}> | ||
<FontAwesomeIcon icon={faTimes} style={tailwind('text-red-400')} /> | ||
</View> | ||
</TouchableOpacity> | ||
</View> | ||
<View style={tailwind('flex w-full h-full')}> | ||
<KeyboardAvoidingView style={tailwind('p-4')}> | ||
<View style={isEdit.isEdit ? tailwind('flex flex-row items-center justify-between pb-1') : {}}> | ||
<Text style={tailwind('font-semibold text-base text-gray-50 mb-2')}>{translate('Core.IssueScreen.type')}</Text> | ||
{isEdit.isEdit ? ( | ||
<Text style={tailwind('text-white')}>{type}</Text> | ||
) : ( | ||
<DropdownActionSheet | ||
value={type} | ||
items={Object.keys(IssueType).map(type => { | ||
return { label: IssueType[type], value: type }; | ||
})} | ||
onChange={setType} | ||
title={translate('Core.IssueScreen.selectType')} | ||
/> | ||
)} | ||
|
||
{error && !type ? <Text style={tailwind('text-red-500 mb-2')}>{error}</Text> : null} | ||
</View> | ||
|
||
<View style={isEdit.isEdit ? tailwind('flex flex-row items-center justify-between pb-1') : {}}> | ||
<Text style={tailwind('font-semibold text-base text-gray-50 mb-2')}>{translate('Core.IssueScreen.category')}</Text> | ||
{isEdit.isEdit ? ( | ||
<Text style={tailwind('text-white')}>{category}</Text> | ||
) : ( | ||
<DropdownActionSheet | ||
value={category} | ||
items={categories?.map(category => { | ||
return { label: category, value: category }; | ||
})} | ||
onChange={setCategory} | ||
title={'Select category'} | ||
/> | ||
)} | ||
{error && !category ? <Text style={tailwind('text-red-500 mb-2')}>{error}</Text> : null} | ||
</View> | ||
<View style={tailwind('mb-4')}> | ||
<Text style={tailwind('font-semibold text-base text-gray-50 mb-2')}>{translate('Core.IssueScreen.report')}</Text> | ||
<TextInput | ||
value={report} | ||
onChangeText={setReport} | ||
numberOfLines={4} | ||
multiline={true} | ||
placeholder={translate('Core.IssueScreen.enterReport')} | ||
placeholderTextColor={getColorCode('text-gray-600')} | ||
style={tailwind('form-input text-white h-28')} | ||
/> | ||
{error && !report?.trim() ? <Text style={tailwind('text-red-500 mb-2')}>{error}</Text> : null} | ||
</View> | ||
<View> | ||
<Text style={tailwind('font-semibold text-base text-gray-50 mb-2')}>{translate('Core.IssueScreen.priority')}</Text> | ||
<DropdownActionSheet | ||
value={priority} | ||
items={Object.keys(IssuePriority).map(priority => { | ||
return { label: IssuePriority[priority], value: priority }; | ||
})} | ||
onChange={setPriority} | ||
title={translate('Core.IssueScreen.selectPriority')} | ||
/> | ||
|
||
{error && !priority ? <Text style={tailwind('text-red-500 mb-2')}>{error}</Text> : null} | ||
</View> | ||
|
||
<TouchableOpacity onPress={saveIssue} disabled={isLoading} style={tailwind('flex')}> | ||
<View style={tailwind('btn bg-gray-900 border border-gray-700 mt-4 ')}> | ||
{isLoading && <ActivityIndicator color={getColorCode('text-gray-50')} style={tailwind('mr-2')} />} | ||
<Text style={tailwind('font-semibold text-lg text-gray-50 text-center')}>{translate('Core.IssueScreen.save')}</Text> | ||
</View> | ||
</TouchableOpacity> | ||
{isEdit.isEdit && ( | ||
<TouchableOpacity onPress={deleteIssues} disabled={isLoading} style={tailwind('flex')}> | ||
<View style={tailwind('btn bg-gray-900 border border-gray-700 mt-4')}> | ||
<Text style={tailwind('font-semibold text-lg text-gray-50 text-center')}>Delete</Text> | ||
</View> | ||
</TouchableOpacity> | ||
)} | ||
</KeyboardAvoidingView> | ||
</View> | ||
</Pressable> | ||
</View> | ||
); | ||
}; | ||
|
||
export default IssueScreen; |
Oops, something went wrong.