diff --git a/src/components/DriveNavigableItem/index.tsx b/src/components/DriveNavigableItem/index.tsx index 503299b6a..f5b836bb0 100644 --- a/src/components/DriveNavigableItem/index.tsx +++ b/src/components/DriveNavigableItem/index.tsx @@ -1,10 +1,10 @@ -import { items } from '@internxt/lib'; import { CaretRight } from 'phosphor-react-native'; import prettysize from 'prettysize'; import React from 'react'; import { TouchableHighlight, View } from 'react-native'; import { useTailwind } from 'tailwind-rn'; import { FolderIcon, getFileTypeIcon } from '../../helpers'; +import { getDisplayName } from '../../helpers/itemNames'; import useGetColor from '../../hooks/useColor'; import globalStyle from '../../styles/global'; import { DriveNavigableItemProps } from '../../types/drive'; @@ -54,7 +54,7 @@ const DriveNavigableItem: React.FC = ({ isLoading, disa numberOfLines={1} ellipsizeMode={'middle'} > - {items.getItemDisplayName(props.data)} + {getDisplayName(props.data)} diff --git a/src/helpers/itemNames.spec.ts b/src/helpers/itemNames.spec.ts new file mode 100644 index 000000000..10ced358a --- /dev/null +++ b/src/helpers/itemNames.spec.ts @@ -0,0 +1,335 @@ +import { DriveItemDataProps } from '../types/drive'; +import { getDisplayName } from './itemNames'; + +describe('getDisplayName', () => { + describe('Folders', () => { + it('should return the folder name as-is', () => { + const folder = { + id: 1, + name: 'Documents', + isFolder: true, + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(folder)).toBe('Documents'); + }); + + it('should handle folder names with special characters', () => { + const folder: DriveItemDataProps = { + id: 1, + name: 'My Folder (2024)', + isFolder: true, + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(folder)).toBe('My Folder (2024)'); + }) as unknown as DriveItemDataProps; + + it('should handle folder names with dots', () => { + const folder: DriveItemDataProps = { + id: 1, + name: 'backup.2024', + isFolder: true, + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(folder)).toBe('backup.2024'); + }); + }); + + describe('Files without extension in name', () => { + it('should append the extension to the file name', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'report', + type: 'pdf', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('report.pdf'); + }); + + it('should handle different file extensions', () => { + const cases = [ + { name: 'image', type: 'jpg', expected: 'image.jpg' }, + { name: 'document', type: 'docx', expected: 'document.docx' }, + { name: 'video', type: 'mp4', expected: 'video.mp4' }, + { name: 'data', type: 'json', expected: 'data.json' }, + ]; + + cases.forEach(({ name, type, expected }) => { + const file: DriveItemDataProps = { + id: 1, + name, + type, + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe(expected); + }); + }); + }); + + describe('Files with extension already in name', () => { + it('should always append the type extension even if present in name', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'report.pdf', + type: 'pdf', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('report.pdf.pdf'); + }); + + it('should append extension regardless of case matching', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'Image.JPG', + type: 'jpg', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('Image.JPG.jpg'); + }); + + it('should always append type to files with multiple dots in name', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'backup.2024.01.15.tar', + type: 'tar', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('backup.2024.01.15.tar.tar'); + }); + + it('should append type even when name ends with same extension', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'document.PDF', + type: 'pdf', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('document.PDF.pdf'); + }); + }); + + describe('Files without type', () => { + it('should return the name as-is when type is undefined', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'unknown', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('unknown'); + }); + + it('should return the name as-is when type is null', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'noextension', + type: undefined, + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('noextension'); + }); + + it('should preserve existing extension in name when type is undefined', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'file.txt', + type: undefined, + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('file.txt'); + }); + }); + + describe('Edge cases', () => { + it('should handle empty type string', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'file', + type: '', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('file'); + }); + + it('should handle type with leading/trailing whitespace', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'document', + type: ' pdf ', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('document. pdf '); + }); + + it('should handle type with only whitespace', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'document', + type: ' ', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('document'); + }); + + it('should handle files with dots but different extension', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'archive.tar', + type: 'gz', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('archive.tar.gz'); + }); + + it('should handle numeric extensions', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'file', + type: '001', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('file.001'); + }); + + it('should handle special characters in extension', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'document', + type: 'pdf~', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('document.pdf~'); + }); + + it('should handle very long extensions', () => { + const longExtension = 'verylongextensionname'; + const file: DriveItemDataProps = { + id: 1, + name: 'file', + type: longExtension, + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe(`file.${longExtension}`); + }); + }); + + describe('Real-world scenarios', () => { + it('should handle common document files', () => { + const scenarios = [ + { name: 'Meeting Notes', type: 'docx', expected: 'Meeting Notes.docx' }, + { name: 'Budget 2024', type: 'xlsx', expected: 'Budget 2024.xlsx' }, + { name: 'Presentation', type: 'pptx', expected: 'Presentation.pptx' }, + ]; + + scenarios.forEach(({ name, type, expected }) => { + const file: DriveItemDataProps = { + id: 1, + name, + type, + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe(expected); + }); + }); + + it('should handle compressed archives with double extensions', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'backup.tar', + type: 'gz', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('backup.tar.gz'); + }); + + it('should handle versioned files', () => { + const file: DriveItemDataProps = { + id: 1, + name: 'document.v2', + type: 'pdf', + isFolder: false, + fileId: 'file-1', + updatedAt: '2025-01-01', + createdAt: '2025-01-01', + } as unknown as DriveItemDataProps; + + expect(getDisplayName(file)).toBe('document.v2.pdf'); + }); + }); +}); diff --git a/src/helpers/itemNames.ts b/src/helpers/itemNames.ts new file mode 100644 index 000000000..26929d1f6 --- /dev/null +++ b/src/helpers/itemNames.ts @@ -0,0 +1,31 @@ +import { DriveItemDataProps } from '../types/drive'; + +/** + * Generates a display name for a drive item (file or folder). + * For folders, returns the name as-is. + * For files, always appends the type extension if present. + * + * @param {DriveItemDataProps} item - The drive item (file or folder) + * @returns {string} The formatted display name + * + * @example + * // Folder + * getDisplayName({ name: 'Documents', isFolder: true }) // 'Documents' + * + * @example + * // File without extension in name + * getDisplayName({ name: 'report', type: 'pdf', isFolder: false }) // 'report.pdf' + * + * @example + * // File with extension in name (always appends type) + * getDisplayName({ name: 'backup.tar', type: 'tar', isFolder: false }) // 'backup.tar.tar' + * + * @example + * // File without type + * getDisplayName({ name: 'unknown', isFolder: false }) // 'unknown' + */ +export const getDisplayName = (item: DriveItemDataProps): string => { + if (item.isFolder || !item.type?.trim()) return item.name; + + return `${item.name}.${item.type}`; +};