forked from polito/students-app
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(achievements): achievements frontend
Implement achievements frontend. Need validation Refs polito#549
- Loading branch information
1 parent
9e46cfb
commit a7f3228
Showing
7 changed files
with
590 additions
and
0 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
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,146 @@ | ||
import React, { useState } from 'react'; | ||
import { | ||
Alert, | ||
Button, | ||
Image, | ||
ScrollView, | ||
StyleSheet, | ||
Text, | ||
TextInput, | ||
TouchableOpacity, | ||
View, | ||
} from 'react-native'; | ||
|
||
// import ImagePicker from 'react-native-image-crop-picker'; | ||
import { Achievement } from '../screens/AchievementsScreen'; | ||
|
||
interface AchievementFormProps { | ||
onSave: (achievement: Achievement, titleName: string) => void; | ||
titles: string[]; | ||
} | ||
|
||
export const AddAchievementForm: React.FC<AchievementFormProps> = ({ | ||
onSave, | ||
titles, | ||
}) => { | ||
const [title, setTitle] = useState(''); | ||
const [description, setDescription] = useState(''); | ||
const [image, setImage] = useState(''); | ||
const [selectedTitle, setSelectedTitle] = useState(titles[0]); | ||
const [isDropdownVisible, setIsDropdownVisible] = useState(false); | ||
|
||
// const pickImage = () => { | ||
// ImagePicker.openPicker({ | ||
// width: 300, | ||
// height: 400, | ||
// cropping: true, | ||
// }) | ||
// .then(img => { | ||
// setImage(img.path); | ||
// }) | ||
// .catch(error => { | ||
// // TODO logger error? | ||
// }); | ||
// }; | ||
|
||
const handleSave = () => { | ||
if (!title.trim()) { | ||
Alert.alert('Validation Error', 'Title is required.'); | ||
return; | ||
} | ||
if (!description.trim()) { | ||
Alert.alert('Validation Error', 'Description is required.'); | ||
return; | ||
} | ||
|
||
const newAchievement: Achievement = { | ||
title, | ||
description, | ||
achieved: false, | ||
image, | ||
}; | ||
onSave(newAchievement, selectedTitle); | ||
// Reset the form | ||
setTitle(''); | ||
setDescription(''); | ||
setImage(''); | ||
setSelectedTitle(titles[0]); | ||
}; | ||
|
||
const handleDropdownToggle = () => { | ||
setIsDropdownVisible(!isDropdownVisible); | ||
}; | ||
|
||
const handleSelectTitle = (t: string) => { | ||
setSelectedTitle(t); | ||
setIsDropdownVisible(false); | ||
}; | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<TextInput | ||
placeholder="Title" | ||
value={title} | ||
onChangeText={setTitle} | ||
style={styles.input} | ||
/> | ||
<TextInput | ||
placeholder="Description" | ||
value={description} | ||
onChangeText={setDescription} | ||
style={styles.input} | ||
/> | ||
<TouchableOpacity onPress={handleDropdownToggle} style={styles.dropdown}> | ||
<Text>{selectedTitle}</Text> | ||
</TouchableOpacity> | ||
{isDropdownVisible && ( | ||
<ScrollView style={styles.dropdownMenu}> | ||
{titles.map((item, index) => ( | ||
<TouchableOpacity | ||
key={index} | ||
onPress={() => handleSelectTitle(item)} | ||
style={styles.dropdownItem} | ||
> | ||
<Text>{item}</Text> | ||
</TouchableOpacity> | ||
))} | ||
</ScrollView> | ||
)} | ||
{/* <Button title="Pick an Image" onPress={pickImage} />*/} | ||
{image && <Image source={{ uri: image }} style={styles.image} />} | ||
<Button title="Save Achievement" onPress={handleSave} /> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
padding: 16, | ||
}, | ||
input: { | ||
borderBottomWidth: 1, | ||
marginBottom: 16, | ||
}, | ||
image: { | ||
width: 200, | ||
height: 200, | ||
marginVertical: 16, | ||
}, | ||
dropdown: { | ||
padding: 12, | ||
borderWidth: 1, | ||
borderColor: '#ccc', | ||
borderRadius: 4, | ||
marginBottom: 16, | ||
}, | ||
dropdownMenu: { | ||
maxHeight: 150, | ||
borderWidth: 1, | ||
borderColor: '#ccc', | ||
borderRadius: 4, | ||
marginBottom: 16, | ||
}, | ||
dropdownItem: { | ||
padding: 12, | ||
}, | ||
}); |
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,93 @@ | ||
import { useEffect, useRef } from 'react'; | ||
import { Dimensions, StyleSheet, View } from 'react-native'; | ||
import Svg, { Circle, Rect } from 'react-native-svg'; | ||
|
||
const getRandomInt = max => Math.floor(Math.random() * max); | ||
|
||
export const ShineAnimation = ({ | ||
speedFactor = 0.05, | ||
starColor = [255, 255, 255], | ||
starCount = 5000, | ||
}) => { | ||
const { width, height } = Dimensions.get('window'); | ||
const starsRef = useRef([]); | ||
|
||
useEffect(() => { | ||
const createStars = count => { | ||
const stars = []; | ||
for (let i = 0; i < count; i++) { | ||
stars.push({ | ||
id: i, | ||
x: getRandomInt(1600) - 800, | ||
y: getRandomInt(900) - 450, | ||
z: getRandomInt(1000), | ||
}); | ||
} | ||
return stars; | ||
}; | ||
|
||
starsRef.current = createStars(starCount); | ||
|
||
const moveStars = (distance: number) => { | ||
starsRef.current.forEach(star => { | ||
star.z -= distance; | ||
if (star.z <= 1) star.z += 1000; | ||
}); | ||
}; | ||
|
||
let prevTime = Date.now(); | ||
|
||
const tick = () => { | ||
const now = Date.now(); | ||
const elapsed = now - prevTime; | ||
prevTime = now; | ||
|
||
moveStars(elapsed * speedFactor); | ||
requestAnimationFrame(tick); | ||
}; | ||
|
||
requestAnimationFrame(tick); | ||
}, [speedFactor, starCount]); | ||
|
||
const renderStars = () => { | ||
const cx = width / 2; | ||
const cy = height / 2; | ||
const starElements = starsRef.current.map(star => { | ||
const x = cx + star.x / (star.z * 0.001); | ||
const y = cy + star.y / (star.z * 0.001); | ||
const d = star.z / 1000.0; | ||
const b = 1 - d * d; | ||
if (x < 0 || x >= width || y < 0 || y >= height) return null; | ||
return ( | ||
<Circle | ||
key={star.id} | ||
cx={x} | ||
cy={y} | ||
r="1" | ||
fill={`rgba(${starColor[0]},${starColor[1]},${starColor[2]},${b})`} | ||
/> | ||
); | ||
}); | ||
return starElements; | ||
}; | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<Svg height="100%" width="100%"> | ||
<Rect x="0" y="0" width="100%" height="100%" fillOpacity={0} /> | ||
{renderStars()} | ||
</Svg> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
right: 0, | ||
bottom: 0, | ||
zIndex: 10, | ||
}, | ||
}); |
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
Oops, something went wrong.