Refactor validation

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2023-07-21 16:34:44 +03:00
parent b7dd1c77af
commit 3c303e0304
17 changed files with 256 additions and 151 deletions

View File

@@ -13,7 +13,11 @@ import styles from '../styles';
import { ROUTE, RootStackParamList } from '../types';
import { MEME_TYPE, Meme, Tag } from '../database';
import { RootState } from '../state';
import { getMemeType } from '../utilities';
import {
getMemeType,
validateMemeDescription,
validateMemeTitle,
} from '../utilities';
import { MemeEditor } from '../components';
const AddMeme = ({
@@ -34,13 +38,13 @@ const AddMeme = ({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
uri.length > 1 ? MEME_TYPE.ALBUM : getMemeType(uri[0].type!);
const [memeTitle, setMemeTitle] = useState('New Meme');
const [memeDescription, setMemeDescription] = useState('');
const [memeTitle, setMemeTitle] = useState(validateMemeTitle('New Meme'));
const [memeDescription, setMemeDescription] = useState(
validateMemeDescription(''),
);
const [memeIsFavorite, setMemeIsFavorite] = useState(false);
const [memeTags, setMemeTags] = useState(new Map<string, Tag>());
const [memeTitleError, setMemeTitleError] = useState<string | undefined>();
const [isSaving, setIsSaving] = useState(false);
const handleSave = async () => {
@@ -72,8 +76,8 @@ const AddMeme = ({
uri: savedUri,
size,
hash,
title: memeTitle,
description: memeDescription,
title: memeTitle.parsed,
description: memeDescription.parsed,
isFavorite: memeIsFavorite,
tags: [...memeTags.values()],
tagsLength: memeTags.size,
@@ -119,8 +123,6 @@ const AddMeme = ({
setMemeDescription={setMemeDescription}
memeTags={memeTags}
setMemeTags={setMemeTags}
memeTitleError={memeTitleError}
setMemeTitleError={setMemeTitleError}
/>
</View>
<View style={[styles.flex, styles.justifyEnd]}>
@@ -128,7 +130,7 @@ const AddMeme = ({
mode="contained"
icon="floppy"
onPress={handleSave}
disabled={!!memeTitleError || isSaving}
disabled={!memeTitle.valid || !memeDescription.valid || isSaving}
loading={isSaving}>
Save
</Button>

View File

@@ -4,7 +4,11 @@ import { Appbar, Button, useTheme } from 'react-native-paper';
import { useNavigation } from '@react-navigation/native';
import { useRealm } from '@realm/react';
import styles from '../styles';
import { generateRandomColor } from '../utilities';
import {
generateRandomColor,
validateColor,
validateTagName,
} from '../utilities';
import { useDimensions } from '../contexts';
import { Tag } from '../database';
import { TagEditor } from '../components';
@@ -15,18 +19,16 @@ const AddTag = () => {
const { orientation } = useDimensions();
const realm = useRealm();
const [tagName, setTagName] = useState('newTag');
const [tagColor, setTagColor] = useState(generateRandomColor());
const [validatedTagColor, setValidatedTagColor] = useState(tagColor);
const [tagNameError, setTagNameError] = useState<string | undefined>();
const [tagColorError, setTagColorError] = useState<string | undefined>();
const [tagName, setTagName] = useState(validateTagName('newTag'));
const [tagColor, setTagColor] = useState(
validateColor(generateRandomColor()),
);
const handleSave = () => {
realm.write(() => {
realm.create(Tag.schema.name, {
name: tagName,
color: tagColor,
name: tagName.parsed,
color: tagColor.parsed,
});
});
@@ -54,12 +56,6 @@ const AddTag = () => {
setTagName={setTagName}
tagColor={tagColor}
setTagColor={setTagColor}
validatedTagColor={validatedTagColor}
setValidatedTagColor={setValidatedTagColor}
tagNameError={tagNameError}
setTagNameError={setTagNameError}
tagColorError={tagColorError}
setTagColorError={setTagColorError}
/>
</View>
<View style={[styles.flex, styles.justifyEnd]}>
@@ -67,7 +63,7 @@ const AddTag = () => {
mode="contained"
icon="floppy"
onPress={handleSave}
disabled={!!tagNameError || !!tagColorError}>
disabled={!tagName.valid || !tagColor.valid}>
Save
</Button>
</View>

View File

@@ -10,6 +10,7 @@ import styles from '../styles';
import { useDimensions } from '../contexts';
import { ROUTE, RootStackParamList } from '../types';
import { Tag } from '../database';
import { validateColor, validateTagName } from '../utilities';
const EditTag = ({
route,
@@ -25,17 +26,13 @@ const EditTag = ({
BSON.UUID.createFromHexString(route.params.id),
)!;
const [tagName, setTagName] = useState(tag.name);
const [tagColor, setTagColor] = useState(tag.color);
const [validatedTagColor, setValidatedTagColor] = useState(tagColor);
const [tagNameError, setTagNameError] = useState<string | undefined>();
const [tagColorError, setTagColorError] = useState<string | undefined>();
const [tagName, setTagName] = useState(validateTagName(tag.name));
const [tagColor, setTagColor] = useState(validateColor(tag.color));
const handleSave = () => {
realm.write(() => {
tag.name = tagName;
tag.color = tagColor;
tag.name = tagName.parsed;
tag.color = tagColor.parsed;
tag.dateModified = new Date();
});
@@ -80,12 +77,6 @@ const EditTag = ({
setTagName={setTagName}
tagColor={tagColor}
setTagColor={setTagColor}
validatedTagColor={validatedTagColor}
setValidatedTagColor={setValidatedTagColor}
tagNameError={tagNameError}
setTagNameError={setTagNameError}
tagColorError={tagColorError}
setTagColorError={setTagColorError}
/>
</View>
<View style={[styles.flex, styles.justifyEnd]}>
@@ -93,7 +84,7 @@ const EditTag = ({
mode="contained"
icon="floppy"
onPress={handleSave}
disabled={!!tagNameError || !!tagColorError}>
disabled={!tagName.valid || !tagColor.valid}>
Save
</Button>
</View>

View File

@@ -12,7 +12,7 @@ import {
} from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
import styles from '../styles';
import { MEME_SORT, SORT_DIRECTION } from '../types';
import { MEME_SORT, SORT_DIRECTION, memesSortQuery } from '../types';
import { getSortIcon, getViewIcon } from '../utilities';
import {
RootState,
@@ -72,7 +72,27 @@ const Memes = () => {
};
const [search, setSearch] = useState('');
const memes = useQuery<Meme>(Meme.schema.name);
const memes = useQuery<Meme>(
Meme.schema.name,
collectionIn => {
let collection = collectionIn;
if (favoritesOnly) collection = collection.filtered('isFavorite == true');
if (filter) collection = collection.filtered('type == $0', filter);
if (search) {
collection = collection.filtered('title CONTAINS[c] $0', search);
}
collection = collection.sorted(
memesSortQuery(sort),
sortDirection === SORT_DIRECTION.DESCENDING,
);
return collection;
},
[sort, sortDirection, favoritesOnly, filter, search],
);
return (
<View

View File

@@ -13,7 +13,11 @@ import { openDocumentTree } from 'react-native-scoped-storage';
import { useDispatch, useSelector } from 'react-redux';
import type {} from 'redux-thunk/extend-redux';
import styles from '../styles';
import { RootState, updateNoMedia, updateStorageUri } from '../state';
import {
RootState,
setNoMedia,
setStorageUri,
} from '../state';
import { useDimensions } from '../contexts';
const settingsScreenStyles = StyleSheet.create({
@@ -68,7 +72,7 @@ const SettingsScreen = () => {
}}
onPress={async () => {
const { uri } = await openDocumentTree(true);
void dispatch(updateStorageUri(uri));
void dispatch(setStorageUri(uri));
}}>
Change External Storage Path
</Button>
@@ -84,7 +88,7 @@ const SettingsScreen = () => {
<Switch
value={noMedia}
onValueChange={value => {
void dispatch(updateNoMedia(value));
void dispatch(setNoMedia(value));
}}
/>
</View>

View File

@@ -99,13 +99,20 @@ const Tags = () => {
const tags = useQuery<Tag>(
Tag.schema.name,
collection =>
collection
.filtered(`name CONTAINS[c] "${search}"`)
.sorted(
tagSortQuery(sort),
sortDirection === SORT_DIRECTION.DESCENDING,
),
collectionIn => {
let collection = collectionIn;
if (search) {
collection = collection.filtered('name CONTAINS[c] $0', search);
}
collection = collection.sorted(
tagSortQuery(sort),
sortDirection === SORT_DIRECTION.DESCENDING,
);
return collection;
},
[search, sort, sortDirection],
);

View File

@@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux';
import { openDocumentTree } from 'react-native-scoped-storage';
import styles from '../styles';
import { noOp } from '../utilities';
import { updateStorageUri } from '../state';
import { setStorageUri } from '../state';
import { useDimensions } from '../contexts';
const Welcome = ({ onWelcomeComplete }: { onWelcomeComplete: () => void }) => {
@@ -16,7 +16,7 @@ const Welcome = ({ onWelcomeComplete }: { onWelcomeComplete: () => void }) => {
const selectStorageLocation = async () => {
const uri = await openDocumentTree(true).catch(noOp);
if (!uri) return;
await dispatch(updateStorageUri(uri.uri));
await dispatch(setStorageUri(uri.uri));
onWelcomeComplete();
};