Mobile Strict Mode and Types (#578)

* better compiler options

* fix types

* fix more types
This commit is contained in:
Utku 2023-02-24 11:11:48 +03:00 committed by GitHub
parent 32ffd5f820
commit 7b739d0b33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 259 additions and 231 deletions

View file

@ -10,7 +10,7 @@ interface Props {
}
export default function DocsSidebar(props: Props) {
const activeSection = props.activePath?.split('/')[0] || props.navigation[0].slug;
const activeSection = props.activePath?.split('/')[0] || props.navigation[0]?.slug;
const activeSectionData = props.navigation.find((section) => section.slug === activeSection);
@ -27,7 +27,7 @@ export default function DocsSidebar(props: Props) {
const Icon = config.sections.find((s) => s.slug === section.slug)?.icon;
return (
<a
href={`/docs/${section.section[0].category[0].url}`}
href={`/docs/${section.section[0]?.category[0]?.url}`}
key={section.slug}
className={clsx(
`doc-sidebar-button flex items-center py-1.5 text-[14px] font-semibold`,

View file

@ -2,7 +2,7 @@ import { PageContextBuiltIn } from 'vite-plugin-ssr';
import { getPost } from './blog';
export async function onBeforeRender(pageContext: PageContextBuiltIn) {
const post = await getPost(pageContext.routeParams['slug']);
const post = await getPost(pageContext.routeParams['slug']!);
return {
pageContext: {

View file

@ -47,13 +47,13 @@ export function getDocs(config: DocsConfig): Record<string, Doc> {
const url = parsePath(path);
if (!url) return null;
const { render, metadata } = parseMarkdown(config.docs[path]);
const { render, metadata } = parseMarkdown(config.docs[path]!);
parsedDocs[url] = {
title: metadata?.name ?? toTitleCase(url.split('/')[2]),
slug: url.split('/')[2],
title: metadata?.name ?? toTitleCase(url.split('/')[2]!),
slug: url.split('/')[2]!,
url,
categoryName: toTitleCase(url.split('/')[1]),
categoryName: toTitleCase(url.split('/')[1]!),
sortByIndex: metadata?.index ?? DEFAULT_INDEX,
html: render
};
@ -77,15 +77,15 @@ export function getDocsNavigation(config: DocsConfig, docs?: Record<string, Doc>
delete clonedDoc.html;
const category = url.split('/')[1],
title = toTitleCase(category),
title = toTitleCase(category!),
existingCategory = categories.findIndex((i) => i.slug === category);
if (existingCategory != -1) {
categories[existingCategory].category.push(clonedDoc);
categories[existingCategory]?.category.push(clonedDoc);
} else {
categories.push({
title,
slug: category,
slug: category!,
index: DEFAULT_INDEX,
category: [clonedDoc]
});
@ -98,7 +98,7 @@ export function getDocsNavigation(config: DocsConfig, docs?: Record<string, Doc>
return cat;
})
// sort categories smallest first doc's index
.sort((a, b) => a.category[0].sortByIndex - b.category[0].sortByIndex);
.sort((a, b) => a.category[0]!.sortByIndex - b.category[0]!.sortByIndex);
navigation.push({
title: section.title,
@ -134,8 +134,8 @@ export function getDoc(url: string, config: DocsConfig): SingleDocResponse {
}
function parsePath(path: string): string | null {
const url = path.split('docs/')[1].split('.md')[0];
if (!url.includes('/')) return null;
const url = path.split('docs/')[1]!.split('.md')[0];
if (!url?.includes('/')) return null;
return url;
}
@ -153,7 +153,7 @@ type DocUrls = { url: string; title: string }[];
export function getNextDoc(
navigation: DocsNavigation,
docUrl: string
): { url: string; title: string } {
): { url: string; title: string } | undefined {
const docUrls: DocUrls = [];
// flatten the navigation
for (const section of navigation) {

View file

@ -7,7 +7,7 @@ export const passToClient = ['pageProps'];
export async function onBeforeRender(pageContext: PageContextBuiltIn) {
return {
pageContext: {
pageProps: getDoc(pageContext.routeParams['*'], config)
pageProps: getDoc(pageContext.routeParams['*']!, config)
}
};
}

View file

@ -11,7 +11,7 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Jamie Pine',
role: 'Founder, Engineer & Designer',
image: teamImages['jamie.jpg'],
image: teamImages['jamie.jpg']!,
socials: {
twitter: 'https://twitter.com/jamiepine',
twitch: 'https://twitch.tv/jamiepinelive',
@ -21,7 +21,7 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Brendan Allan',
role: 'Rust Engineer',
image: teamImages['brendan.jpg'],
image: teamImages['brendan.jpg']!,
socials: {
twitter: 'https://twitter.com/brendonovichdev',
twitch: 'https://twitch.tv/brendonovich',
@ -31,7 +31,7 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Oscar Beaumont',
role: 'Rust Engineer',
image: teamImages['oscar.jpg'],
image: teamImages['oscar.jpg']!,
socials: {
twitter: 'https://twitter.com/oscartbeaumont',
twitch: 'https://twitch.tv/oscartbeaumont',
@ -41,16 +41,16 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Ericson Soares',
role: 'Rust Engineer',
image: teamImages['ericson.jpg'],
image: teamImages['ericson.jpg']!,
socials: {
twitter: 'https://twitter.com/fogodev',
github: 'https://github.com/fogodev'
}
},
{
name: 'Utku Bakir',
name: 'Utku Bakır',
role: 'React Native Engineer',
image: teamImages['utku.jpg'],
image: teamImages['utku.jpg']!,
socials: {
github: 'https://github.com/utkubakir'
}
@ -58,7 +58,7 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Haden Fletcher',
role: 'Engineer & Designer',
image: teamImages['haden.jpg'],
image: teamImages['haden.jpg']!,
socials: {
twitter: 'https://twitter.com/heymaxichrome',
twitch: 'https://twitch.tv/maxichrome',
@ -68,7 +68,7 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Jake Robinson',
role: 'Rust Engineer',
image: teamImages['jake.jpg'],
image: teamImages['jake.jpg']!,
socials: {
github: 'https://github.com/brxken128'
}
@ -76,7 +76,7 @@ const teamMembers: Array<TeamMemberProps> = [
{
name: 'Mihail Dounaev',
role: 'Graphic Designer',
image: teamImages['mihail.jpg'],
image: teamImages['mihail.jpg']!,
socials: {
twitter: 'https://twitter.com/mmmintdesign',
dribbble: 'https://dribbble.com/mmmint'
@ -89,109 +89,109 @@ const investors: Array<TeamMemberProps> = [
name: 'Joseph Jacks',
role: 'Founder, OSSC',
investmentRound: 'Lead Seed',
image: investorImages['josephjacks.jpg']
image: investorImages['josephjacks.jpg']!
},
{
name: 'Guillermo Rauch',
role: 'CEO, Vercel',
investmentRound: 'Co-Lead Seed',
image: investorImages['guillermo.jpg']
image: investorImages['guillermo.jpg']!
},
{
name: 'Naval Ravikant',
role: 'Founder, AngelList',
investmentRound: 'Co-Lead Seed',
image: investorImages['naval.jpg']
image: investorImages['naval.jpg']!
},
{
name: 'Neha Narkhede',
role: 'Confluent, Apache Kafka',
investmentRound: 'Seed',
image: investorImages['neha.jpg']
image: investorImages['neha.jpg']!
},
{
name: 'Austen Allred',
role: 'CEO, Bloom Institute of Technology',
investmentRound: 'Seed',
image: investorImages['austen.jpg']
image: investorImages['austen.jpg']!
},
{
name: 'Tom Preston-Werner',
role: 'Founder, GitHub',
investmentRound: 'Seed',
image: investorImages['TOM.jpg']
image: investorImages['TOM.jpg']!
},
{
name: 'Tobias Lütke',
role: 'CEO, Shopify',
investmentRound: 'Seed',
image: investorImages['tobiaslutke.jpg']
image: investorImages['tobiaslutke.jpg']!
},
{
name: 'Justin Hoffman',
role: 'Former VP Sales, Elasticsearch',
investmentRound: 'Seed',
image: investorImages['justinhoffman.jpg']
image: investorImages['justinhoffman.jpg']!
},
{
name: 'Ry Walker',
role: 'Founder, Astronomer',
investmentRound: 'Seed',
image: investorImages['rywalker.jpg']
image: investorImages['rywalker.jpg']!
},
{
name: 'Zachary Smith',
role: 'Head of Edge Infrastructure, Equinix',
investmentRound: 'Seed',
image: investorImages['zacharysmith.jpg']
image: investorImages['zacharysmith.jpg']!
},
{
name: 'Sanjay Poonen',
role: 'Former COO, VMware',
investmentRound: 'Seed',
image: investorImages['sanjay.jpg']
image: investorImages['sanjay.jpg']!
},
{
name: 'David Mytton',
role: 'CEO, console.dev',
investmentRound: 'Seed',
image: investorImages['davidmytton.jpg']
image: investorImages['davidmytton.jpg']!
},
{
name: 'Peer Richelsen',
role: 'CEO, Cal.com',
investmentRound: 'Seed',
image: investorImages['peer.jpg']
image: investorImages['peer.jpg']!
},
{
name: 'Lester Lee',
role: 'Founder, Slapdash',
investmentRound: 'Seed',
image: investorImages['lesterlee.jpg']
image: investorImages['lesterlee.jpg']!
},
{
name: 'Haoyuan Li',
role: 'Founder, Alluxio',
investmentRound: 'Seed',
image: investorImages['haoyuan.jpg']
image: investorImages['haoyuan.jpg']!
},
{
name: 'Augusto Marietti',
role: 'CEO, Kong',
investmentRound: 'Seed',
image: investorImages['augusto.jpg']
image: investorImages['augusto.jpg']!
},
{
name: 'Vijay Sharma',
role: 'CEO, Belong',
investmentRound: 'Seed',
image: investorImages['vijay.jpg']
image: investorImages['vijay.jpg']!
},
{
name: 'Naveen R',
role: 'Founder, NocoDB',
investmentRound: 'Seed',
image: investorImages['naveen.jpg']
image: investorImages['naveen.jpg']!
}
];

View file

@ -41,10 +41,10 @@ export function parseMarkdown(markdownRaw: string): MarkdownParsed {
return text;
} else {
const rawText = rawSplit[index],
meta = rawText.split(/\r?\n/)[0].trim(),
meta = rawText!.split(/\r?\n/)[0]!.trim(),
kind = meta.split(' ')[0],
name = meta.split(' ')[1],
extra = meta.substring(kind.length + name.length + 2),
extra = meta.substring(kind!.length + name!.length + 2),
content = text.substring(meta.length + 1, text.length).trim();
// console.log({ kind, name, extra, content });

View file

@ -1,4 +1,4 @@
// @ts-check
// @ts-ignore
let fs = require('fs-extra');
let path = require('path');

View file

@ -1,7 +1,7 @@
import { useState } from 'react';
import { queryClient, useBridgeMutation } from '@sd/client';
import { Input } from '~/components/form/Input';
import Dialog from '~/components/layout/Dialog';
import { Input } from '~/components/primitive/Input';
import { currentLibraryStore } from '~/utils/nav';
type Props = {

View file

@ -35,7 +35,7 @@ const DrawerLibraryManager = () => {
: 'border-b-app-box border-sidebar-line bg-sidebar-button rounded-t-md'
)}
>
<Text style={tw`text-ink text-sm font-semibold`}>{currentLibrary.config.name}</Text>
<Text style={tw`text-ink text-sm font-semibold`}>{currentLibrary?.config.name}</Text>
<MotiView
animate={{
rotate: dropdownClosed ? '0deg' : '180deg',
@ -57,13 +57,13 @@ const DrawerLibraryManager = () => {
<View
style={twStyle(
'mt-1 p-2',
currentLibrary.uuid === library.uuid && 'bg-accent rounded'
currentLibrary?.uuid === library.uuid && 'bg-accent rounded'
)}
>
<Text
style={twStyle(
'text-ink text-sm font-semibold',
currentLibrary.uuid === library.uuid && 'text-white'
currentLibrary?.uuid === library.uuid && 'text-white'
)}
>
{library.config.name}

View file

@ -36,7 +36,7 @@ type DrawerLocationsProp = {
const DrawerLocations = ({ stackName }: DrawerLocationsProp) => {
const navigation = useNavigation<DrawerNavigationHelpers>();
const importModalRef = useRef<ModalRef>();
const importModalRef = useRef<ModalRef>(null);
const { data: locations } = useLibraryQuery(['locations.list'], { keepPreviousData: true });
@ -62,7 +62,7 @@ const DrawerLocations = ({ stackName }: DrawerLocationsProp) => {
))}
</View>
{/* Add Location */}
<Pressable onPress={() => importModalRef.current.present()}>
<Pressable onPress={() => importModalRef.current?.present()}>
<View style={tw`border-app-line/80 mt-1 rounded border border-dashed`}>
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>Add Location</Text>
</View>

View file

@ -37,7 +37,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
const { data: tags } = useLibraryQuery(['tags.list'], { keepPreviousData: true });
const createTagModalRef = useRef<ModalRef>();
const createTagModalRef = useRef<ModalRef>(null);
return (
<CollapsibleView
@ -49,7 +49,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
{tags?.map((tag) => (
<DrawerTagItem
key={tag.id}
tagName={tag.name}
tagName={tag.name!}
onPress={() =>
navigation.navigate(stackName, {
screen: 'Tag',
@ -61,7 +61,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
))}
</View>
{/* Add Tag */}
<Pressable onPress={() => createTagModalRef.current.present()}>
<Pressable onPress={() => createTagModalRef.current?.present()}>
<View style={tw`border-app-line/80 mt-1 rounded border border-dashed`}>
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>Add Tag</Text>
</View>

View file

@ -14,7 +14,7 @@ import FileItem from './FileItem';
import FileRow from './FileRow';
type ExplorerProps = {
data: ExplorerData;
data: ExplorerData | undefined;
};
const Explorer = ({ data }: ExplorerProps) => {
@ -22,7 +22,7 @@ const Explorer = ({ data }: ExplorerProps) => {
const [layoutMode, setLayoutMode] = useState<'grid' | 'list'>(getExplorerStore().layoutMode);
function changeLayoutMode(kind) {
function changeLayoutMode(kind: 'grid' | 'list') {
// We need to keep layoutMode as a state to make sure flash-list re-renders.
setLayoutMode(kind);
getExplorerStore().layoutMode = kind;
@ -35,7 +35,7 @@ const Explorer = ({ data }: ExplorerProps) => {
navigation.push('Location', { id: data.item.location_id, path: data.item.materialized_path });
} else {
setData(data);
modalRef.current.present();
modalRef.current?.present();
}
}

View file

@ -1,3 +1,4 @@
import { PropsWithChildren } from 'react';
import { Image, View } from 'react-native';
import { DocumentDirectoryPath } from 'react-native-fs';
import { ExplorerItem, isObject, isPath } from '@sd/client';
@ -18,7 +19,7 @@ type FileThumbProps = {
export const getThumbnailUrlById = (casId: string) =>
`${DocumentDirectoryPath}/thumbnails/${encodeURIComponent(casId)}.webp`;
const FileThumbWrapper = ({ children, size = 1 }) => (
const FileThumbWrapper = ({ children, size = 1 }: PropsWithChildren<{ size: number }>) => (
<View style={[tw`items-center justify-center`, { width: 80 * size, height: 80 * size }]}>
{children}
</View>
@ -38,7 +39,7 @@ export default function FileThumb({ data, size = 1, kind }: FileThumbProps) {
);
const casId = isObject(data) ? data.item.file_paths[0]?.cas_id : data.item.cas_id;
if (!casId) return undefined;
if (!casId) return null;
// Icon
let icon = undefined;

View file

@ -12,7 +12,7 @@ type Props = {
const InfoTagPills = ({ data, style }: Props) => {
const objectData = data ? (isObject(data) ? data.item : data.item.object) : null;
const tagsQuery = useLibraryQuery(['tags.getForObject', objectData?.id], {
const tagsQuery = useLibraryQuery(['tags.getForObject', objectData?.id ?? -1], {
enabled: Boolean(objectData)
});
@ -25,7 +25,7 @@ const InfoTagPills = ({ data, style }: Props) => {
{/* Kind */}
<InfoPill
containerStyle={tw`mr-1`}
text={isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]}
text={isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]!}
/>
{/* Extension */}
{item.extension && <InfoPill text={item.extension} containerStyle={tw`mr-1`} />}
@ -33,7 +33,7 @@ const InfoTagPills = ({ data, style }: Props) => {
{tagsQuery.data?.map((tag) => (
<InfoPill
key={tag.id}
text={tag.name}
text={tag.name ?? 'Unnamed Tag'}
containerStyle={twStyle('mr-1', { backgroundColor: tag.color + 'CC' })}
textStyle={tw`text-white`}
/>

View file

@ -0,0 +1,38 @@
import React from 'react';
import WheelColorPicker from 'react-native-wheel-color-picker';
import { tw } from '~/lib/tailwind';
type ColorPickerProps = {
color: string;
onColorChangeComplete: (color: string) => void;
};
const defaultPalette = [
tw.color('blue-500'),
tw.color('red-500'),
tw.color('green-500'),
tw.color('yellow-500'),
tw.color('purple-500'),
tw.color('pink-500'),
tw.color('gray-500'),
tw.color('black'),
tw.color('white')
];
const ColorPicker = ({ color, onColorChangeComplete }: ColorPickerProps) => {
return (
<WheelColorPicker
autoResetSlider
gapSize={0}
thumbSize={40}
sliderSize={24}
shadeSliderThumb
color={color}
onColorChangeComplete={onColorChangeComplete}
swatchesLast={false}
palette={defaultPalette as string[]}
/>
);
};
export default ColorPicker;

View file

@ -31,7 +31,7 @@ const ModalHandle = (props: ModalHandle) => (
>
{props.showCloseButton && (
<Pressable
onPress={() => props.modalRef.current.close()}
onPress={() => props.modalRef.current?.close()}
style={tw`bg-app-button absolute top-5 right-4 h-7 w-7 items-center justify-center rounded-full`}
>
<X size={16} color="white" weight="bold" />
@ -101,7 +101,7 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
return (
<>
{props.trigger && (
<Pressable onPress={() => modalRef.current.present()}>{props.trigger}</Pressable>
<Pressable onPress={() => modalRef.current?.present()}>{props.trigger}</Pressable>
)}
<BottomSheetModal
ref={modalRef}
@ -126,7 +126,7 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
style={tw`flex-1`}
size="lg"
disabled={props.loading} // Disables Close button if loading
onPress={() => modalRef.current.close()}
onPress={() => modalRef.current?.close()}
>
<Text style={tw`text-ink text-sm font-medium`}>Close</Text>
</Button>

View file

@ -1,6 +1,7 @@
import { PropsWithChildren } from 'react';
import { FlatList } from 'react-native';
export default function VirtualizedListWrapper({ children }) {
export default function VirtualizedListWrapper({ children }: PropsWithChildren) {
return (
<FlatList
data={[]}

View file

@ -13,11 +13,13 @@ const sortOptions = {
date_last_opened: 'Date Last Opened'
};
type SortByType = keyof typeof sortOptions;
const ArrowUpIcon = () => <ArrowUp weight="bold" size={16} color={tw.color('ink')} />;
const ArrowDownIcon = () => <ArrowDown weight="bold" size={16} color={tw.color('ink')} />;
const SortByMenu = () => {
const [sortBy, setSortBy] = useState('name');
const [sortBy, setSortBy] = useState<SortByType>('name');
const [sortDirection, setSortDirection] = useState('asc' as 'asc' | 'desc');
return (
@ -32,7 +34,9 @@ const SortByMenu = () => {
{Object.entries(sortOptions).map(([value, text]) => (
<MenuItem
key={value}
icon={value === sortBy && (sortDirection === 'asc' ? ArrowUpIcon : ArrowDownIcon)}
icon={
value === sortBy ? (sortDirection === 'asc' ? ArrowUpIcon : ArrowDownIcon) : undefined
}
text={text}
value={value}
onSelect={() => {
@ -42,7 +46,7 @@ const SortByMenu = () => {
}
// Reset sort direction to descending
sortDirection === 'asc' && setSortDirection('desc');
setSortBy(value);
setSortBy(value as SortByType);
}}
/>
))}

View file

@ -1,14 +1,15 @@
import * as ML from 'expo-media-library';
import { forwardRef, useCallback } from 'react';
import { Alert, Platform, Text, View } from 'react-native';
import { Alert, Text, View } from 'react-native';
import DocumentPicker from 'react-native-document-picker';
import { useLibraryMutation } from '@sd/client';
// import RFS from 'react-native-fs';
import { Modal, ModalRef } from '~/components/layout/Modal';
import { Button } from '~/components/primitive/Button';
import useForwardedRef from '~/hooks/useForwardedRef';
import { tw } from '~/lib/tailwind';
// import RFS from 'react-native-fs';
// import * as ML from 'expo-media-library';
// WIP component
const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
const modalRef = useForwardedRef(ref);
@ -29,6 +30,8 @@ const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
presentationStyle: 'pageSheet'
});
if (!response) return;
createLocation({
path: decodeURIComponent(response.uri.replace('file://', '')),
indexer_rules_ids: []
@ -43,70 +46,70 @@ const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
Alert.alert('TODO');
return;
// Check if we have full access to the photos library
let permission = await ML.getPermissionsAsync();
// {"accessPrivileges": "none", "canAskAgain": true, "expires": "never", "granted": false, "status": "undetermined"}
// // Check if we have full access to the photos library
// let permission = await ML.getPermissionsAsync();
// // {"accessPrivileges": "none", "canAskAgain": true, "expires": "never", "granted": false, "status": "undetermined"}
if (
permission.status === ML.PermissionStatus.UNDETERMINED ||
(permission.status === ML.PermissionStatus.DENIED && permission.canAskAgain)
) {
permission = await ML.requestPermissionsAsync();
}
// if (
// permission.status === ML.PermissionStatus.UNDETERMINED ||
// (permission.status === ML.PermissionStatus.DENIED && permission.canAskAgain)
// ) {
// permission = await ML.requestPermissionsAsync();
// }
// Permission Denied
if (permission.status === ML.PermissionStatus.DENIED) {
Alert.alert(
'Permission required',
'You need to grant access to your photos library to import your photos/videos.'
);
return;
}
// // Permission Denied
// if (permission.status === ML.PermissionStatus.DENIED) {
// Alert.alert(
// 'Permission required',
// 'You need to grant access to your photos library to import your photos/videos.'
// );
// return;
// }
// Limited Permission (Can't access path)
if (permission.accessPrivileges === 'limited') {
Alert.alert(
'Limited access',
'You need to grant full access to your photos library to import your photos/videos.'
);
return;
}
// // Limited Permission (Can't access path)
// if (permission.accessPrivileges === 'limited') {
// Alert.alert(
// 'Limited access',
// 'You need to grant full access to your photos library to import your photos/videos.'
// );
// return;
// }
// If android return error for now...
if (Platform.OS !== 'ios') {
Alert.alert('Not supported', 'Not supported for now...');
return;
}
// // If android return error for now...
// if (Platform.OS !== 'ios') {
// Alert.alert('Not supported', 'Not supported for now...');
// return;
// }
// And for IOS we are assuming every asset is under the same path (which is not the case)
// // And for IOS we are assuming every asset is under the same path (which is not the case)
// file:///Users/xxxx/Library/Developer/CoreSimulator/Devices/F99C471F-C9F9-458D-8B87-BCC4B46C644C/data/Media/DCIM/100APPLE/IMG_0004.JPG
// file:///var/mobile/Media/DCIM/108APPLE/IMG_8332.JPG
// // file:///Users/xxxx/Library/Developer/CoreSimulator/Devices/F99C471F-C9F9-458D-8B87-BCC4B46C644C/data/Media/DCIM/100APPLE/IMG_0004.JPG
// // file:///var/mobile/Media/DCIM/108APPLE/IMG_8332.JPG
const firstAsset = (await ML.getAssetsAsync({ first: 1 })).assets[0];
// const firstAsset = (await ML.getAssetsAsync({ first: 1 })).assets[0];
if (!firstAsset) return;
// if (!firstAsset) return;
// Gets asset uri: ph://CC95F08C-88C3-4012-9D6D-64A413D254B3
const assetId = firstAsset.id;
// Gets Actual Path
const path = (await ML.getAssetInfoAsync(assetId)).localUri;
// // Gets asset uri: ph://CC95F08C-88C3-4012-9D6D-64A413D254B3
// const assetId = firstAsset?.id;
// // Gets Actual Path
// const path = (await ML.getAssetInfoAsync(assetId)).localUri;
const libraryPath = Platform.select({
android: '',
ios: path.replace('file://', '').split('Media/DCIM/')[0] + 'Media/DCIM/'
});
// const libraryPath = Platform.select({
// android: '',
// ios: path.replace('file://', '').split('Media/DCIM/')[0] + 'Media/DCIM/'
// });
createLocation({
path: libraryPath,
indexer_rules_ids: []
});
// createLocation({
// path: libraryPath,
// indexer_rules_ids: []
// });
// const assets = await ML.getAssetsAsync({ mediaType: ML.MediaType.photo });
// assets.assets.map(async (i) => {
// console.log((await ML.getAssetInfoAsync(i)).localUri);
// });
}, [createLocation]);
}, []);
// const testFN = useCallback(async () => {
// console.log(RFS.PicturesDirectoryPath);

View file

@ -9,7 +9,7 @@ type Props = {
};
const DeleteLibraryModal = ({ trigger, onSubmit, libraryUuid }: Props) => {
const modalRef = useRef<ModalRef>();
const modalRef = useRef<ModalRef>(null);
const { mutate: deleteLibrary, isLoading: deleteLibLoading } = useBridgeMutation(
'library.delete',
@ -19,12 +19,13 @@ const DeleteLibraryModal = ({ trigger, onSubmit, libraryUuid }: Props) => {
onSubmit?.();
},
onSettled: () => {
modalRef.current.close();
modalRef.current?.close();
}
}
);
return (
<ConfirmModal
ref={modalRef}
title="Delete Library"
description="Deleting a library will permanently the database, the files themselves will not be deleted."
ctaLabel="Delete"

View file

@ -9,7 +9,7 @@ type Props = {
};
const DeleteLocationModal = ({ trigger, onSubmit, locationId }: Props) => {
const modalRef = useRef<ModalRef>();
const modalRef = useRef<ModalRef>(null);
const { mutate: deleteLoc, isLoading: deleteLocLoading } = useLibraryMutation(
'locations.delete',
@ -18,7 +18,7 @@ const DeleteLocationModal = ({ trigger, onSubmit, locationId }: Props) => {
onSubmit?.();
},
onSettled: () => {
modalRef.current.close();
modalRef.current?.close();
}
}
);

View file

@ -9,19 +9,20 @@ type Props = {
};
const DeleteTagModal = ({ trigger, onSubmit, tagId }: Props) => {
const modalRef = useRef<ModalRef>();
const modalRef = useRef<ModalRef>(null);
const { mutate: deleteTag, isLoading: deleteTagLoading } = useLibraryMutation('tags.delete', {
onSuccess: () => {
onSubmit?.();
},
onSettled: () => {
modalRef.current.close();
modalRef.current?.close();
}
});
return (
<ConfirmModal
ref={modalRef}
title="Delete Tag"
description="Are you sure you want to delete this tag? This cannot be undone and tagged files will be unlinked."
ctaLabel="Delete"

View file

@ -71,14 +71,14 @@ export const ActionsModal = () => {
<View style={tw`flex-1 px-4`}>
<View style={tw`flex flex-row items-center`}>
{/* Thumbnail/Icon */}
<Pressable onPress={() => fileInfoRef.current.present()}>
<Pressable onPress={() => fileInfoRef.current?.present()}>
<FileThumb data={data} size={1} />
</Pressable>
<View style={tw`ml-2 flex-1`}>
{/* Name + Extension */}
<Text style={tw`text-base font-bold text-gray-200`} numberOfLines={1}>
{item.name}
{item.extension && `.${item.extension}`}
{item?.name}
{item?.extension && `.${item?.extension}`}
</Text>
<View style={tw`flex flex-row`}>
<Text style={tw`text-ink-faint text-xs`}>
@ -86,12 +86,12 @@ export const ActionsModal = () => {
</Text>
<Text style={tw`text-ink-faint text-xs`}>
{' '}
{dayjs(item.date_created).format('MMM Do YYYY')}
{dayjs(item?.date_created).format('MMM Do YYYY')}
</Text>
</View>
<InfoTagPills data={data} />
</View>
<FavoriteButton style={tw`mr-4`} data={objectData} />
{objectData && <FavoriteButton style={tw`mr-4`} data={objectData} />}
</View>
<View style={tw`my-3`} />
{/* Actions */}
@ -99,7 +99,7 @@ export const ActionsModal = () => {
<ActionsItem
icon={Info}
title="Show Info"
onPress={() => fileInfoRef.current.present()}
onPress={() => fileInfoRef.current?.present()}
/>
</ActionsContainer>
<ActionsContainer style={tw`mt-2`}>

View file

@ -31,7 +31,7 @@ function MetaItem({ title, value, icon }: MetaItemProps) {
<>
<View style={tw`flex flex-row items-center`}>
<View style={tw`w-30 flex flex-row items-center`}>
{icon && <Icon color="white" size={18} style={tw`mr-1`} />}
{Icon && <Icon color="white" size={18} style={tw`mr-1`} />}
<Text style={tw`text-sm font-medium text-white`}>{title}</Text>
</View>
<Text style={tw`text-sm text-gray-400`}>{value}</Text>
@ -42,7 +42,7 @@ function MetaItem({ title, value, icon }: MetaItemProps) {
}
type FileInfoModalProps = {
data: ExplorerItem;
data: ExplorerItem | null;
};
const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
@ -69,13 +69,13 @@ const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
{data && (
<ModalScrollView style={tw`flex-1 p-4`}>
{/* Back Button */}
<Pressable onPress={() => modalRef.current.close()} style={tw`absolute z-10 ml-4`}>
<Pressable onPress={() => modalRef.current?.close()} style={tw`absolute z-10 ml-4`}>
<CaretLeft color={tw.color('accent')} size={20} weight="bold" />
</Pressable>
{/* File Icon / Name */}
<View style={tw`items-center`}>
<FileThumb data={data} size={1.6} />
<Text style={tw`mt-2 text-base font-bold text-gray-200`}>{item.name}</Text>
<Text style={tw`mt-2 text-base font-bold text-gray-200`}>{item?.name}</Text>
<InfoTagPills data={data} style={tw`mt-3`} />
</View>
{/* Details */}
@ -99,19 +99,21 @@ const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
<MetaItem
icon={Clock}
title="Created"
value={dayjs(item.date_created).format('MMM Do YYYY')}
value={dayjs(item?.date_created).format('MMM Do YYYY')}
/>
{/* Indexed */}
<MetaItem
icon={Barcode}
title="Indexed"
value={dayjs(item.date_indexed).format('MMM Do YYYY')}
value={dayjs(item?.date_indexed).format('MMM Do YYYY')}
/>
{filePathData && (
<>
{/* TODO: Note */}
<MetaItem icon={Snowflake} title="Content ID" value={filePathData.cas_id} />
{filePathData.cas_id && (
<MetaItem icon={Snowflake} title="Content ID" value={filePathData.cas_id} />
)}
{/* Checksum */}
{filePathData?.integrity_checksum && (
<MetaItem

View file

@ -3,9 +3,9 @@ import { Pressable, Text, View } from 'react-native';
import ColorPicker from 'react-native-wheel-color-picker';
import { queryClient, useLibraryMutation } from '@sd/client';
import { FadeInAnimation } from '~/components/animation/layout';
import { Input } from '~/components/form/Input';
import { Modal, ModalRef } from '~/components/layout/Modal';
import { Button } from '~/components/primitive/Button';
import { Input } from '~/components/primitive/Input';
import useForwardedRef from '~/hooks/useForwardedRef';
import { tw, twStyle } from '~/lib/tailwind';
@ -29,12 +29,12 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
},
onSettled: () => {
// Close modal
modalRef.current.dismiss();
modalRef.current?.dismiss();
}
});
useEffect(() => {
modalRef.current.snapToIndex(showPicker ? 1 : 0);
modalRef.current?.snapToIndex(showPicker ? 1 : 0);
}, [modalRef, showPicker]);
return (
@ -70,27 +70,7 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
{showPicker && (
<FadeInAnimation>
<View style={tw`mt-4 h-64`}>
<ColorPicker
autoResetSlider
gapSize={0}
thumbSize={40}
sliderSize={24}
shadeSliderThumb
color={tagColor}
onColorChangeComplete={(color) => setTagColor(color)}
swatchesLast={false}
palette={[
tw.color('blue-500'),
tw.color('red-500'),
tw.color('green-500'),
tw.color('yellow-500'),
tw.color('purple-500'),
tw.color('pink-500'),
tw.color('gray-500'),
tw.color('black'),
tw.color('white')
]}
/>
<ColorPicker color={tagColor} onColorChangeComplete={(color) => setTagColor(color)} />
</View>
</FadeInAnimation>
)}

View file

@ -1,11 +1,11 @@
import { forwardRef, useEffect, useState } from 'react';
import { Pressable, Text, View } from 'react-native';
import ColorPicker from 'react-native-wheel-color-picker';
import { ColorValue, Pressable, Text, View } from 'react-native';
import { Tag, queryClient, useLibraryMutation } from '@sd/client';
import { FadeInAnimation } from '~/components/animation/layout';
import ColorPicker from '~/components/form/ColorPicker';
import { Input } from '~/components/form/Input';
import { Modal, ModalRef } from '~/components/layout/Modal';
import { Button } from '~/components/primitive/Button';
import { Input } from '~/components/primitive/Input';
import useForwardedRef from '~/hooks/useForwardedRef';
import { tw, twStyle } from '~/lib/tailwind';
@ -17,8 +17,8 @@ type Props = {
const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
const modalRef = useForwardedRef(ref);
const [tagName, setTagName] = useState(props.tag.name);
const [tagColor, setTagColor] = useState(props.tag.color);
const [tagName, setTagName] = useState(props.tag.name!);
const [tagColor, setTagColor] = useState(props.tag.color!);
const [showPicker, setShowPicker] = useState(false);
const { mutate: updateTag, isLoading } = useLibraryMutation('tags.update', {
@ -31,12 +31,12 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
props.onSubmit?.();
},
onSettled: () => {
modalRef.current.dismiss();
modalRef.current?.dismiss();
}
});
useEffect(() => {
modalRef.current.snapToIndex(showPicker ? 1 : 0);
modalRef.current?.snapToIndex(showPicker ? 1 : 0);
}, [modalRef, showPicker]);
return (
@ -63,32 +63,12 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
style={twStyle({ backgroundColor: tagColor }, 'h-5 w-5 rounded-full')}
/>
{/* TODO: Make this editable. Need to make sure color is a valid hexcode and update the color on picker etc. etc. */}
<Input editable={false} value={tagColor} style={tw`ml-2 flex-1`} />
<Input editable={false} value={tagColor as string} style={tw`ml-2 flex-1`} />
</View>
{showPicker && (
<FadeInAnimation>
<View style={tw`mt-4 h-64`}>
<ColorPicker
autoResetSlider
gapSize={0}
thumbSize={40}
sliderSize={24}
shadeSliderThumb
color={tagColor}
onColorChangeComplete={(color) => setTagColor(color)}
swatchesLast={false}
palette={[
tw.color('blue-500'),
tw.color('red-500'),
tw.color('green-500'),
tw.color('yellow-500'),
tw.color('purple-500'),
tw.color('pink-500'),
tw.color('gray-500'),
tw.color('black'),
tw.color('white')
]}
/>
<ColorPicker color={tagColor} onColorChangeComplete={(color) => setTagColor(color)} />
</View>
</FadeInAnimation>
)}

View file

@ -79,7 +79,7 @@ export function createReactNativeClient(): TRPCWebSocketClient {
body = JSON.stringify(outgoing);
}
SDCore.sd_core_msg(body).then((rawData) => {
SDCore.sd_core_msg(body).then((rawData: string) => {
const data = JSON.parse(rawData);
if (Array.isArray(data)) {
for (const payload of data) {

View file

@ -58,7 +58,7 @@ if (Platform.OS === 'ios') {
const App = lazy(async () => {
const keys = await AsyncStorage.getAllKeys();
const values = await AsyncStorage.multiGet(keys);
values.forEach(([key, value]) => _localStorage.set(key, value));
values.forEach(([key, value]) => _localStorage.set(key, value!));
return await import('./App');
});

View file

@ -11,7 +11,7 @@ export default function LocationScreen({ navigation, route }: SharedScreenProps<
'locations.getExplorerData',
{
location_id: id,
path: path || '',
path: path ?? '',
limit: 100,
cursor: null
}
@ -26,14 +26,14 @@ export default function LocationScreen({ navigation, route }: SharedScreenProps<
});
} else {
navigation.setOptions({
title: data?.context.name
title: data?.context.name ?? 'Location'
});
}
}, [data, navigation, path]);
useEffect(() => {
getExplorerStore().locationId = id;
getExplorerStore().path = path;
getExplorerStore().path = path ?? '';
}, [id, path]);
return <Explorer data={data} />;

View file

@ -6,7 +6,15 @@ export default function NotFoundScreen({ navigation }: RootStackScreenProps<'Not
return (
<View style={tw`flex-1 items-center justify-center p-5`}>
<Text style={tw`text-xl font-bold`}>This screen doesn&apos;t exist.</Text>
<TouchableOpacity onPress={() => navigation.replace('Root')} style={tw`mt-4 py-4`}>
<TouchableOpacity
onPress={() =>
navigation.replace('Root', {
screen: 'Home',
params: { screen: 'OverviewStack', params: { screen: 'Overview' } }
})
}
style={tw`mt-4 py-4`}
>
<Text style={tw`text-ink-dull text-sm`}>Go to home screen!</Text>
</TouchableOpacity>
</View>

View file

@ -12,7 +12,7 @@ export default function TagScreen({ navigation, route }: SharedScreenProps<'Tag'
useEffect(() => {
// Set screen title to tag name.
navigation.setOptions({
title: data?.context.name
title: data?.context.name ?? 'Tag'
});
}, [data?.context.name, navigation]);

View file

@ -1,9 +1,9 @@
import React from 'react';
import { Text, View } from 'react-native';
import { useBridgeQuery } from '@sd/client';
import { Input } from '~/components/form/Input';
import Card from '~/components/layout/Card';
import Divider from '~/components/primitive/Divider';
import { Input } from '~/components/primitive/Input';
import { tw } from '~/lib/tailwind';
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';

View file

@ -3,9 +3,9 @@ import React from 'react';
import { Controller, useForm } from 'react-hook-form';
import { Alert, Text, View } from 'react-native';
import { useBridgeMutation, useLibraryContext } from '@sd/client';
import { Input } from '~/components/form/Input';
import { Switch } from '~/components/form/Switch';
import { Button } from '~/components/primitive/Button';
import { Input } from '~/components/primitive/Input';
import { Switch } from '~/components/primitive/Switch';
import { SettingsContainer } from '~/components/settings/SettingsContainer';
import { SettingsItem } from '~/components/settings/SettingsItem';
import { useAutoForm } from '~/hooks/useAutoForm';

View file

@ -11,7 +11,7 @@ import { tw, twStyle } from '~/lib/tailwind';
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
function TagItem({ tag, index }: { tag: Tag; index: number }) {
const updateTagModalRef = useRef<ModalRef>();
const updateTagModalRef = useRef<ModalRef>(null);
const renderRightActions = (
progress: Animated.AnimatedInterpolation<number>,
@ -29,7 +29,7 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
style={[tw`flex flex-row items-center`, { transform: [{ translateX: translate }] }]}
>
<UpdateTagModal tag={tag} ref={updateTagModalRef} onSubmit={() => swipeable.close()} />
<AnimatedButton size="md" onPress={() => updateTagModalRef.current.present()}>
<AnimatedButton size="md" onPress={() => updateTagModalRef.current?.present()}>
<Pen size={18} color="white" />
</AnimatedButton>
<DeleteTagModal
@ -55,7 +55,7 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
>
<View style={tw`flex flex-row items-center justify-between`}>
<View style={tw`flex flex-row`}>
<View style={twStyle({ backgroundColor: tag.color }, 'h-4 w-4 rounded-full')} />
<View style={twStyle({ backgroundColor: tag.color! }, 'h-4 w-4 rounded-full')} />
<Text style={tw`text-ink ml-3`}>{tag.name}</Text>
</View>
<CaretRight color={tw.color('ink-dull')} size={18} />

View file

@ -1,6 +1,7 @@
import {
DrawerNavigationState,
ParamListBase,
Route,
getFocusedRouteNameFromRoute
} from '@react-navigation/native';
import { valtioPersist } from '@sd/client';
@ -9,7 +10,9 @@ export const currentLibraryStore = valtioPersist('sdActiveLibrary', {
id: null as string | null
});
export const getActiveRouteFromState = function (state: any) {
export const getActiveRouteFromState = function (
state: any
): Partial<Route<string, object | undefined>> {
if (!state.routes || state.routes.length === 0 || state.index >= state.routes.length) {
return state;
}

View file

@ -1,14 +1,24 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
"jsx": "react-native",
"lib": ["DOM", "ESNext"],
"moduleResolution": "node",
"resolveJsonModule": true,
"skipLibCheck": true,
"target": "ESNext",
"module": "ESNext",
"noEmit": true,
"paths": {
"~/*": ["./src/*"]
},
"jsx": "react-native"
"strict": true,
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true
},
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"],
"references": [
{
"path": "../../packages/client"

View file

@ -2,25 +2,21 @@
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Default",
"compilerOptions": {
// Actual type stuff
"strict": true,
"jsx": "react-jsx",
"esModuleInterop": true,
// Various configs
"skipLibCheck": true,
"preserveWatchOutput": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
// Project references stuff
"noUncheckedIndexedAccess": true,
"composite": true,
"declaration": true,
"emitDeclarationOnly": true,
// Module stuff
"moduleResolution": "node",
"resolveJsonModule": true,
"module": "ESNext",
"target": "ESNext",
// Extra types
"types": ["vite-plugin-svgr/client", "vite/client"]
}
}

View file

@ -14,7 +14,7 @@ function Index() {
const currentLibrary = libraries.data.find((l) => l.uuid === currentLibraryCache.id);
const libraryId = currentLibrary ? currentLibrary.uuid : libraries.data[0].uuid;
const libraryId = currentLibrary ? currentLibrary.uuid : libraries.data[0]?.uuid;
return <Navigate to={`${libraryId}/overview`} />;
}

View file

@ -35,7 +35,7 @@ export const EncryptFileDialog = ({ ...props }: EncryptDialogProps) => {
const keys = useLibraryQuery(['keys.list']);
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
onSuccess: (data) => {
UpdateKey(data[0]);
UpdateKey(data[0] ?? '');
}
});

View file

@ -56,9 +56,9 @@ export const EraseFileDialog = (props: EraseDialogProps) => {
min={1}
step={1}
defaultValue={[4]}
onValueChange={(e) => {
setPasses(e);
form.setValue('passes', e[0]);
onValueChange={(val) => {
setPasses(val);
form.setValue('passes', val[0] ?? 1);
}}
/>
</div>

View file

@ -41,7 +41,7 @@ export const KeyViewerDialog = (props: KeyViewerDialogProps) => {
const keys = useLibraryQuery(['keys.list'], {
onSuccess: (data) => {
if (key === '' && data.length !== 0) {
setKey(data[0].uuid);
setKey(data[0]?.uuid ?? '');
}
}
});

View file

@ -145,7 +145,7 @@ export const VirtualizedList = memo(({ data, context, onScroll }: Props) => {
kind="list"
isSelected={getExplorerStore().selectedRowIndex === virtualRow.index}
index={virtualRow.index}
item={data[virtualRow.index]}
item={data[virtualRow.index]!}
/>
) : (
[...Array(amountOfColumns)].map((_, i) => {

View file

@ -1,8 +1,8 @@
import cryptoRandomString from 'crypto-random-string';
import { Eye, EyeSlash, Info } from 'phosphor-react';
import { useEffect, useRef, useState } from 'react';
import { Algorithm, useLibraryMutation, useLibraryQuery } from '@sd/client';
import { Button, CategoryHeading, Input, Select, SelectOption, Switch, cva, tw } from '@sd/ui';
import { Algorithm, useLibraryMutation } from '@sd/client';
import { Button, CategoryHeading, Input, Select, SelectOption, Switch, tw } from '@sd/ui';
import { getHashingAlgorithmSettings } from '../../screens/settings/library/KeysSetting';
import Slider from '../primitive/Slider';
import { Tooltip } from '../tooltip/Tooltip';
@ -67,12 +67,12 @@ export function KeyMounter() {
min={8}
step={4}
defaultValue={[64]}
onValueChange={(e) => {
setSliderValue(e);
setKey(generatePassword(e[0]));
onValueChange={(val) => {
setSliderValue(val);
setKey(generatePassword(val[0] ?? 8));
}}
onClick={() => {
setKey(generatePassword(sliderValue[0]));
setKey(generatePassword(sliderValue[0] ?? 8));
}}
/>
</div>

View file

@ -6,7 +6,7 @@ export const useCurrentOnboardingScreenKey = (): string | null => {
const { pathname } = useLocation();
if (pathname.startsWith(`/${ONBOARDING_ROUTE_PREFIX_NAME}/`)) {
return pathname.split('/')[2];
return pathname.split('/')[2] || null;
}
return null;

View file

@ -18,9 +18,9 @@ export function MacTrafficLights(props: TrafficLightsProps) {
return (
<div data-tauri-drag-region className={clsx('group flex flex-row space-x-[7.5px]', className)}>
<TrafficLight type="close" onClick={onClose} colorful={focused} />
<TrafficLight type="minimize" onClick={onMinimize} colorful={focused} />
<TrafficLight type="fullscreen" onClick={onFullscreen} colorful={focused} />
<TrafficLight type="close" onClick={onClose} colorful={focused ?? false} />
<TrafficLight type="minimize" onClick={onMinimize} colorful={focused ?? false} />
<TrafficLight type="fullscreen" onClick={onFullscreen} colorful={focused ?? false} />
</div>
);
}

View file

@ -312,7 +312,7 @@ const table: Record<string, HashingAlgorithm> = {
// not sure of a suitable place for this function
export const getHashingAlgorithmSettings = (hashingAlgorithm: string): HashingAlgorithm => {
return table[hashingAlgorithm];
return table[hashingAlgorithm] || { name: 'Argon2id', params: 'Standard' };
};
// not sure of a suitable place for this function