Merge pull request #7 from mudabbir-ahmad/Week4Act3

Week4Act3
This commit is contained in:
bobbert authored and GitHub committed 2025-12-04 18:31:24 +00:00
commit 967c9342e1
10 files changed
+281 -34

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ const Component = () => {
// View ----------------------- // View -----------------------
return ( return (
<Text></Text> <View></View>
); );
}; };
+14
View File
@@ -9,6 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@expo/vector-icons": "^15.0.3", "@expo/vector-icons": "^15.0.3",
"@react-native-picker/picker": "^2.11.4",
"@react-navigation/native": "^7.1.18", "@react-navigation/native": "^7.1.18",
"@react-navigation/native-stack": "^7.5.1", "@react-navigation/native-stack": "^7.5.1",
"expo": "^54.0.20", "expo": "^54.0.20",
@@ -3054,6 +3055,19 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@react-native-picker/picker": {
"version": "2.11.4",
"resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.11.4.tgz",
"integrity": "sha512-Kf8h1AMnBo54b1fdiVylP2P/iFcZqzpMYcglC28EEFB1DEnOjsNr6Ucqc+3R9e91vHxEDnhZFbYDmAe79P2gjA==",
"license": "MIT",
"workspaces": [
"example"
],
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/@react-native/assets-registry": { "node_modules/@react-native/assets-registry": {
"version": "0.81.5", "version": "0.81.5",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz",
+1
View File
@@ -10,6 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@expo/vector-icons": "^15.0.3", "@expo/vector-icons": "^15.0.3",
"@react-native-picker/picker": "^2.11.4",
"@react-navigation/native": "^7.1.18", "@react-navigation/native": "^7.1.18",
"@react-navigation/native-stack": "^7.5.1", "@react-navigation/native-stack": "^7.5.1",
"expo": "^54.0.20", "expo": "^54.0.20",
+114
View File
@@ -0,0 +1,114 @@
import {KeyboardAvoidingView, ScrollView, StyleSheet, Text, TextInput, View} from "react-native";
import {Picker} from "@react-native-picker/picker";
import {Button, ButtonTray} from "./Button";
import Icons from "./Icons";
const Form = ({children, onSubmit, onCancel, submitLabel, submitIcon}) => {
// Initialisation -------------
// State ----------------------
// Handlers -------------------
// View -----------------------
return (
<KeyboardAvoidingView style={styles.formContainer}>
<ScrollView contentContainerStyle={styles.formItems}>
{children}
</ScrollView>
<ButtonTray>
<Button label='Cancel' icon={<Icons.Close/>} onClick={onCancel}/>
<Button label={submitLabel} icon={submitIcon} onClick={onSubmit}/>
</ButtonTray>
</KeyboardAvoidingView>
);
};
const InputText = ({label, value, onChange}) => {
// Initialisation -------------
// State ----------------------
// Handlers -------------------
// View -----------------------
return (
<View style={styles.item}>
<Text style={styles.itemLabel}>{label}</Text>
<TextInput
value={value}
onChangeText={onChange}
style={styles.itemTextInput}
/>
</View>
)
};
const InputSelect = ({label, prompt, options, value, onChange}) => {
// Initialisation -------------
// State ----------------------
// Handlers -------------------
// View -----------------------
return (
<View style={styles.item}>
<Text style={styles.itemLabel}>{label}</Text>
<Picker
mode="dropdown"
selectedValue={value}
onValueChange={onChange}
style={styles.itemPickerStyle}
>
<Picker.Item
value={null}
label={prompt}
style={styles.itemPickerPromptStyle}
/>
{
options.map((option, index) => <Picker.Item
key={index}
value={option.value}
label={option.label}
/>)
}
</Picker>
</View>
)
};
// Compose components
Form.InputText = InputText;
Form.InputSelect = InputSelect;
// Styles
const styles = StyleSheet.create({
itemLabel: {
color: 'gray',
fontSize: 16,
margin: 5,
},
itemTextInput: {
height: 50,
paddingLeft: 10,
fontSize: 16,
backgroundColor: 'white',
borderRadius: 7,
borderWidth: 1,
borderColor: 'lightgray',
},
formItems: {
gap: 5,
},
formContainer: {
gap: 10
},
itemPickerStyle: {
height: 50,
backgroundColor: 'whitesmoke',
},
itemPickerPromptStyle: {
color: 'gray',
},
});
export default Form;
+6 -2
View File
@@ -3,7 +3,7 @@ import FullWidthImage from "react-native-fullwidth-image";
import {Button, ButtonTray} from "../../UI/Button"; import {Button, ButtonTray} from "../../UI/Button";
import Icons from "../../UI/Icons.js" import Icons from "../../UI/Icons.js"
const ModuleView = ({module, onDelete}) => { const ModuleView = ({module, onDelete, onModify}) => {
// Initialisation ------------- // Initialisation -------------
// State ---------------------- // State ----------------------
// Handlers ------------------- // Handlers -------------------
@@ -35,7 +35,11 @@ const ModuleView = ({module, onDelete}) => {
</View> </View>
<ButtonTray> <ButtonTray>
<Button icon={<Icons.Edit/>} label={"Modify"}/> <Button
icon={<Icons.Edit/>}
label={"Modify"}
onClick={onModify}
/>
<Button <Button
icon={<Icons.Delete/>} icon={<Icons.Delete/>}
label={"Delete"} label={"Delete"}
+103
View File
@@ -0,0 +1,103 @@
import {StyleSheet, Text, TextInput, View} from "react-native";
import {useState} from "react";
import Icons from "../../UI/Icons";
import Form from "../../UI/Form";
const defaultModule = {
ModuleID: null,
ModuleCode: null,
ModuleName: null,
ModuleLevel: null,
ModuleLeaderID: null,
ModuleLeaderName: null,
ModuleImage: null,
};
const ModuleForm = ({originalModule, onSubmit, onCancel}) => {
// Initialisation -------------
defaultModule.ModuleID = Math.floor(100000 + Math.random() * 900000);
defaultModule.ModuleImage = 'https://images.freeimages.com/images/small-preview/cf5/cellphone-1313194.jpg';
const levels = [
{value: 3, label: '3 (Foundation)'},
{value: 4, label: '4 (First Year)'},
{value: 5, label: '5 (Second Year)'},
{value: 6, label: '6 (Third Year)'},
{value: 7, label: '7 (Masters)'},
];
// State ----------------------
const [module, setModule] = useState(originalModule || defaultModule);
// Handlers -------------------
const handleChange = (field, value) => {
setModule({...module, [field]: value})
};
const handleSubmit = () => onSubmit(module);
// View -----------------------
const submitLabel = originalModule ? 'Modify' : 'Add';
const submitIcon = originalModule ? <Icons.Edit/> : <Icons.Add/>;
return (
<Form
onSubmit={handleSubmit}
onCancel={onCancel}
submitLabel={submitLabel}
submitIcon={submitIcon}
>
<Form.InputText
label='Module Code'
value={module.ModuleCode}
onChange={(value) => handleChange('ModuleCode', value)}
/>
<Form.InputText
label='Module Name'
value={module.ModuleName}
onChange={(value) => handleChange('ModuleName', value)}
/>
<Form.InputSelect
label='Module Level'
prompt={'Select module level...'}
options={levels}
value={module.ModuleLevel}
onChange={(value) => handleChange('ModuleLevel', value)}
/>
<Form.InputText
label='Module Leader Name'
value={module.ModuleLeaderName}
onChange={(value) => handleChange('ModuleLeaderName', value)}
/>
<Form.InputText
label='Module Image URL'
value={module.ModuleImage}
onChange={(value) => handleChange('ModuleImage', value)}
/>
{/* This is to test whether the correct Data was being stored in Local State */}
{/*<Text> {module.ModuleCode} {module.ModuleName} </Text>*/}
</Form>
);
};
const styles = StyleSheet.create({
formContainer: {},
item: {},
});
export default ModuleForm;
+4 -20
View File
@@ -1,36 +1,20 @@
import {StyleSheet, Text} from "react-native"; import {StyleSheet, Text, TextInput, View} from "react-native";
import Screen from "../layout/Screen"; import Screen from "../layout/Screen";
import {Button, ButtonTray} from "../UI/Button"; import ModuleForm from "../entity/modules/moduleForm";
import Icons from "../UI/Icons";
const defaultModule = {
ModuleID: Math.floor(100000 + Math.random()*900000),
ModuleCode: "CI6330",
ModuleName: "Mobile Application Development",
ModuleLevel: 6,
ModuleLeaderID: 1,
ModuleLeaderName: "Graeme Jones",
ModuleImage: 'https://images.freeimages.com/images/small-preview/cf5/cellphone-1313194.jpg',
};
export const ModuleAddScreen = ({navigation, route}) => { export const ModuleAddScreen = ({navigation, route}) => {
// Initialisation ------------- // Initialisation -------------
const { onAdd } = route.params; const {onAdd} = route.params;
// State ---------------------- // State ----------------------
// Handlers ------------------- // Handlers -------------------
const handleAdd = () => onAdd(defaultModule);
const handleCancel = navigation.goBack; const handleCancel = navigation.goBack;
// View ----------------------- // View -----------------------
return ( return (
<Screen style={styles.container}> <Screen style={styles.container}>
<Text>Add</Text> <ModuleForm onSubmit={onAdd} onCancel={handleCancel}/>
<ButtonTray>
<Button label='Cancel' onClick={handleCancel} />
<Button label='Add' icon={<Icons.Add/>} onClick={handleAdd} />
</ButtonTray>
</Screen> </Screen>
); );
}; };
+16 -6
View File
@@ -15,7 +15,6 @@ const ModuleListScreen = ({navigation}) => {
// State ---------------------- // State ----------------------
const [modules, setModules] = useState(initialModules); const [modules, setModules] = useState(initialModules);
// Handlers ------------------- // Handlers -------------------
const handleDelete = (module) => const handleDelete = (module) =>
@@ -27,17 +26,28 @@ const ModuleListScreen = ({navigation}) => {
navigation.goBack(); navigation.goBack();
} }
const handleAdd = (module) => setModules([ ...modules, module]); const handleAdd = (module) => setModules([...modules, module]);
const handleModify = (updatedModule) => setModules(
modules.map((module) => (module.ModuleID === updatedModule.ModuleID) ? updatedModule : module),
);
const onAdd = (module) => { const onAdd = (module) => {
handleAdd(module); handleAdd(module);
navigation.goBack(); navigation.goBack();
}; };
const onModify = (module) => {
handleModify(module);
navigation.replace('ModuleViewScreen', { module, onDelete, onModify });
};
const goToViewScreen = (module) => const goToViewScreen = (module) =>
navigation.navigate('ModuleViewScreen', {module, onDelete}); navigation.navigate('ModuleViewScreen', {module, onDelete, onModify});
const goToAddScreen = () =>
navigation.navigate('ModuleAddScreen', {onAdd});
const goToAddScreen = () => navigation.navigate('ModuleAddScreen', {onAdd});
// View ----------------------- // View -----------------------
@@ -45,9 +55,9 @@ const ModuleListScreen = ({navigation}) => {
<Screen> <Screen>
{/*<RenderCount/>*/} {/*<RenderCount/>*/}
<ButtonTray> <ButtonTray>
<Button label='Add' icon={<Icons.Add/>} onClick={goToAddScreen} /> <Button label='Add' icon={<Icons.Add/>} onClick={goToAddScreen}/>
</ButtonTray> </ButtonTray>
<ModuleList modules={modules} onSelect={goToViewScreen} /> <ModuleList modules={modules} onSelect={goToViewScreen}/>
</Screen> </Screen>
); );
}; };
+12 -2
View File
@@ -1,14 +1,24 @@
import {StyleSheet, Text} from "react-native"; import {StyleSheet, Text} from "react-native";
import Screen from "../layout/Screen"; import Screen from "../layout/Screen";
import ModuleForm from "../entity/modules/moduleForm";
export const ModuleModifyScreen = () => { export const ModuleModifyScreen = ({navigation, route}) => {
// Initialisation ------------- // Initialisation -------------
const {module, onModify} = route.params;
// State ---------------------- // State ----------------------
// Handlers ------------------- // Handlers -------------------
const handleCancel = () => navigation.navigate.goBack();
// View ----------------------- // View -----------------------
return ( return (
<Screen style={styles.container}> <Screen style={styles.container}>
<Text>Modify</Text> <ModuleForm
originalModule={module}
onSubmit={onModify}
onCancel={handleCancel}
/>
</Screen> </Screen>
); );
}; };
+10 -3
View File
@@ -3,16 +3,23 @@ import Screen from "../layout/Screen";
import ModuleView from "../entity/modules/ModuleView"; import ModuleView from "../entity/modules/ModuleView";
export const ModuleViewScreen = ({route}) => { export const ModuleViewScreen = ({navigation, route}) => {
// Initialisation ------------- // Initialisation -------------
const {module, onDelete} = route.params; const {module, onDelete, onModify} = route.params;
// State ---------------------- // State ----------------------
// Handlers ------------------- // Handlers -------------------
const goToModifyScreen = () => navigation.replace("ModuleModifyScreen", { module, onModify });
// View ----------------------- // View -----------------------
return (<Screen> return (<Screen>
<ModuleView module={module} onDelete={onDelete}></ModuleView> <ModuleView
module={module}
onDelete={onDelete}
onModify={goToModifyScreen}
/>
</Screen>); </Screen>);
}; };