Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map Note View UI Changes & Published Notes Redirect #121

Merged
merged 13 commits into from
Feb 25, 2024
2 changes: 1 addition & 1 deletion .github/workflows/Native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '16.x'
node-version: '18'

- name: Install dependencies
run: |
Expand Down
38 changes: 38 additions & 0 deletions __tests__/ImageModal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ImageModal from '../lib/screens/mapPage/ImageModal';

Enzyme.configure({ adapter: new Adapter() });

jest.mock('../lib/components/ThemeProvider', () => ({
useTheme: () => ({
theme: {
text: '#000',
},
}),
}));

describe("ImageModal", () => {
const mockImages = [
{ uri: "https://example.com/image1.jpg" },
{ uri: "https://example.com/image2.jpg" }
];

it("renders without crashing", () => {
const wrapper = shallow(<ImageModal isVisible={true} onClose={() => {}} images={mockImages} />);
expect(wrapper).toMatchSnapshot();
});

it("displays the correct number of images", () => {
const wrapper = shallow(<ImageModal isVisible={true} onClose={() => {}} images={mockImages} />);
expect(wrapper.find('Image').length).toBe(mockImages.length);
});

it("handles the close button press", () => {
const mockOnClose = jest.fn();
const wrapper = shallow(<ImageModal isVisible={true} onClose={mockOnClose} images={mockImages} />);
wrapper.find('TouchableOpacity').simulate('press');
expect(mockOnClose).toHaveBeenCalled();
});
});
16 changes: 16 additions & 0 deletions __tests__/NoteDetailModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,20 @@ describe("NoteDetailModal", () => {
const wrapper = shallow(<NoteDetailModal />);
expect(wrapper).toMatchSnapshot();
});

it("should respond to image button press", () => {
const wrapper = shallow(<NoteDetailModal />);
const imageButton = wrapper.findWhere(node => node.prop('testID') === 'imageButton').first();
expect(imageButton.exists()).toBe(true); // Ensure the button exists

imageButton.props().onPress();
});

it("should respond to video button press", () => {
const wrapper = shallow(<NoteDetailModal />);
const videoButton = wrapper.findWhere(node => node.prop('testID') === 'videoButton').first();
expect(videoButton.exists()).toBe(true); // Ensure the button exists

videoButton.props().onPress();
});
});
3 changes: 3 additions & 0 deletions __tests__/__snapshots__/ImageModal.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ImageModal renders without crashing 1`] = `ShallowWrapper {}`;
2 changes: 1 addition & 1 deletion lib/screens/AddNoteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ const AddNoteScreen: React.FC<AddNoteScreenProps> = ({ navigation, route }) => {
style={{ flex: 1 }}
ref={scrollViewRef}
contentContainerStyle={{ paddingBottom: keyboardOpen ? keyboardHeight : 20 }}
>
>
<RichEditor data-testid="RichEditor"
ref={(r) => (richTextRef.current = r)}
style={{...NotePageStyles().input, flex: 1, minHeight: 650 }}
Expand Down
41 changes: 32 additions & 9 deletions lib/screens/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { formatToLocalDateString } from "../components/time";
import { ThemeProvider, useTheme } from '../components/ThemeProvider';
import Constants from "expo-constants";
import DropDownPicker from 'react-native-dropdown-picker';
import NoteDetailModal from "./mapPage/NoteDetailModal";

const user = User.getInstance();

Expand All @@ -44,6 +45,8 @@ const HomeScreen: React.FC<HomeScreenProps> = ({ navigation, route }) => {
const [open, setOpen] = useState(false);
const [value, setValue] = useState(initialItems[0].value);
const [items, setItems] = useState(initialItems);
const [selectedNote, setSelectedNote] = useState<Note | undefined>(undefined);
const [isModalVisible, setModalVisible] = useState(false);

const { theme } = useTheme();

Expand Down Expand Up @@ -420,15 +423,28 @@ const HomeScreen: React.FC<HomeScreenProps> = ({ navigation, route }) => {
key={item.id}
activeOpacity={1}
style={styles.noteContainer}
onPress={() =>
navigation.navigate("EditNote", {
note: item,
onSave: (editedNote: Note) => {
updateNote(editedNote);
refreshPage();
},
})
}
onPress={() => {
if (!item.published) {
navigation.navigate("EditNote", {
note: item,
onSave: (editedNote: Note) => {
updateNote(editedNote);
refreshPage();
},
});
} else {
console.log(item);
const formattedNote = {
...item,
time: formatToLocalDateString(new Date(item.time)),
description: item.text,
images:
item.media.map((mediaItem: { uri: any; }) => ({ uri: mediaItem.uri }))
};
setSelectedNote(formattedNote);
setModalVisible(true);
}
}}
>
<View style={{ flexDirection: "row", alignItems: "center" }}>
{IsImage ? (
Expand Down Expand Up @@ -559,6 +575,13 @@ const HomeScreen: React.FC<HomeScreenProps> = ({ navigation, route }) => {
<Ionicons name="add-outline" size={32} color={theme.primaryColor} style={{ fontFamily: 'Ionicons_' }} />
</TouchableOpacity>
</View>

<NoteDetailModal
isVisible={isModalVisible}
onClose={() => setModalVisible(false)}
note={selectedNote}
/>

</View>
);
};
Expand Down
5 changes: 3 additions & 2 deletions lib/screens/mapPage/ExploreScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const ExploreScreen = () => {
};

const onViewNote = (note) => {
console.log(note);
setSelectedNote(note);
setModalVisible(true);
};
Expand Down Expand Up @@ -584,10 +585,10 @@ const [state, setState] = useState({
</View>
</View>
</View>
))}
))}

</Animated.ScrollView>
<NoteDetailModal
<NoteDetailModal
isVisible={isModalVisible}
onClose={() => setModalVisible(false)}
note={selectedNote}
Expand Down
108 changes: 108 additions & 0 deletions lib/screens/mapPage/ImageModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React, { useState } from 'react';
import {
Modal,
View,
ScrollView,
Text,
Image,
ActivityIndicator,
StyleSheet,
TouchableOpacity,
Dimensions,
} from 'react-native';
import { useTheme } from "../../components/ThemeProvider";

interface ImageType {
uri: string;
}

interface Props {
isVisible: boolean;
onClose: () => void;
images: ImageType[];
}

const { width, height } = Dimensions.get("window");

const ImageModal: React.FC<Props> = ({ isVisible, onClose, images }) => {
const [imageLoadedState, setImageLoadedState] = useState<{ [key: string]: boolean }>({});
const [isImageTouched, setIsImageTouched] = useState(false);
const theme = useTheme();

const handleLoad = (uri: string) => {
setImageLoadedState((prev) => ({ ...prev, [uri]: true }));
};

const handleImageTouchStart = () => setIsImageTouched(!isImageTouched);

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingTop: 45,
width: '100%',
backgroundColor: theme.primaryColor,
},
imageContainer: {
alignItems: 'center',
width: '100%',
backgroundColor: theme.primaryColor,
},
image: {
width: width,
height: width,
},
noImagesText: {
alignSelf: 'center',
justifyContent: 'center',
marginTop: 200,
color: theme.text,
},
closeButton: {
height: 40,
width: 75,
alignItems: 'center',
justifyContent: 'center',
marginTop: 20,
backgroundColor: '#ddd',
padding: 10,
borderRadius: 5,
marginBottom: 30,
},
});

return (
<Modal animationType="slide" transparent={false} visible={isVisible} onRequestClose={onClose}>
<View style={styles.container}>
<ScrollView
style={{ height: isImageTouched ? "80%" : "50%" }}
onTouchStart={images && images.length > 2 ? handleImageTouchStart : undefined}
>
{images && images.length > 0 ? (
images.map((image, index) => (
<View key={index} style={styles.imageContainer}>
{!imageLoadedState[image.uri] && (
<ActivityIndicator size="large" color="#0000ff" />
)}
<Image
source={{ uri: image.uri }}
style={styles.image}
onLoad={() => handleLoad(image.uri)}
/>
</View>
))
) : (
<Text style={styles.noImagesText}>No images</Text>
)}
</ScrollView>

<TouchableOpacity style={styles.closeButton} onPress={onClose}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</Modal>
);
};

export default ImageModal;
Loading
Loading