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

Some linting #51

Merged
merged 30 commits into from
Feb 12, 2025
Merged

Some linting #51

merged 30 commits into from
Feb 12, 2025

Conversation

harperreed
Copy link
Owner

@harperreed harperreed commented Feb 12, 2025

Summary by CodeRabbit

  • New Features

    • Rebranded the application as "Orbiting" with refreshed visuals and revised app metadata.
    • Introduced a welcome modal and streamlined onboarding experience.
    • Added support for Progressive Web App (PWA) installation, enabling a native-like web experience.
  • Enhancements

    • Upgraded UI components for improved accessibility and navigation across key screens.
    • Expanded customization in settings with new theme options and font size adjustments.
    • Optimized the web deployment process for better performance and offline support.

Copy link
Contributor

coderabbitai bot commented Feb 12, 2025

Walkthrough

The changes shift the project from a Hugo‐based static generator to an Expo/Node.js-based application architecture. New GitHub Actions workflows for linting, testing, and deployments have been added while deployment configurations (Firebase, Netlify, Wrangler) now reference Expo and Node.js. The application is rebranded from “chat” to “Orbiting” with expanded web and PWA support. Tests, contexts, components, and utilities have been updated or newly introduced, and many legacy Hugo files and configurations have been removed.

Changes

File(s) Change Summary
.github/workflows/expo-lint.yml, .github/workflows/expo-test.yml, .github/workflows/firebase-hosting-merge.yml, .github/workflows/firebase-hosting-pull-request.yml Added new and updated existing GitHub Actions workflows for linting, testing, and deploying using Node.js and Expo (replacing Hugo)
firebase.json, netlify.toml, wrangler.toml Updated deployment configurations: public directory, build commands, and environment variables now target Node.js/Expo builds
packages/chat/app.json, packages/chat/README.md, packages/chat/package.json Rebranded app (name “Orbiting”), expanded web configuration, and added new scripts/dependencies (PWA support, service worker generation)
packages/chat/.eslintrc.js, **/__tests__/* Introduced ESLint configuration and modified tests for accessibility, error handling, and UI interactions
packages/chat/app/components/*, packages/chat/app/context/*, packages/chat/app/hooks/* Added/updated components (ErrorBoundary, WelcomeModal, InstallPWA, TabBar), context providers, and custom hooks (useIsMounted) for improved UX
packages/chat/app/utils/* Added new utilities for service worker registration, settings storage, and updated message pagination
packages/chat/app/themes/index.ts, biome.json Introduced new theme definitions and code formatting configuration
packages/hugo/**/* Removed all Hugo-related files, configurations, assets, and build scripts

Sequence Diagram(s)

sequenceDiagram
    participant B as Browser
    participant I as Index Component
    participant R as registerServiceWorker
    B->>I: Window load event
    I->>R: Import and call registerServiceWorker
    R->>B: Attempt to register /sw.js
    B-->>R: Registration result (success/failure)
    R-->>I: Log outcome
Loading
sequenceDiagram
    participant B as Browser
    participant A as InstallPWA Component
    participant U as User
    B->>A: Trigger beforeinstallprompt event
    A->>A: Prevent default and store prompt event
    A->>U: Display "Install App" button
    U->>A: Click button to install
    A->>B: Invoke prompt() method on stored event
    B-->>A: Return user choice
    A->>A: Process installation result
Loading

Poem

In lines of code, a fresh start unfurled,
Workflows and themes join in a vibrant swirl.
Hugo steps back as Node takes the lead,
Orbiting dreams empower the new creed.
With hooks and tests, our code takes flight,
A bright new journey in digital light!

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@harperreed harperreed changed the base branch from main to expo-cleanup February 12, 2025 04:56
Copy link

netlify bot commented Feb 12, 2025

Deploy Preview for orbit-ing ready!

Name Link
🔨 Latest commit 37b95fe
🔍 Latest deploy log https://app.netlify.com/sites/orbit-ing/deploys/67ac2a0e1bfa6000087a0bd1
😎 Deploy Preview https://deploy-preview-51--orbit-ing.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 68 (🔴 down 26 from production)
Accessibility: 97 (🟢 up 20 from production)
Best Practices: 100 (no change from production)
SEO: 80 (🔴 down 20 from production)
PWA: 60 (🔴 down 20 from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 42

🔭 Outside diff range comments (8)
packages/chat/app/components/BigTextDisplay.tsx (1)

49-70: 🧹 Nitpick (assertive)

Edge case in calculateAndSetFontSize.

When text is shorter (e.g. 1–2 chars), resetting font size to max is logical. Consider verifying with test cases for boundary text lengths.

packages/chat/app/settings.tsx (1)

200-275: 🧹 Nitpick (assertive)

Style definitions are coherent.

The consistent usage of Paper theme colors ensures a unified look & feel. The naming is intuitive, though consider grouping advanced styling in separate files as the component grows.

packages/chat/app/__tests__/HomeScreen.test.tsx (2)

1-118: ⚠️ Potential issue

Fix the react-native-shake package linking issue.

The pipeline is failing due to an unlinked package. This needs to be addressed before merging.

#!/bin/bash
# Install and link the package
npm install react-native-shake
cd ios && pod install && cd ..
🧰 Tools
🪛 GitHub Actions: Expo Tests

[error] 8-8: The package 'react-native-shake' doesn't seem to be linked. Make sure: - You have run 'pod install' - You rebuilt the app after installing the package - You are not using Expo Go.


52-70: 🧹 Nitpick (assertive)

Add test coverage for font size edge cases.

Consider adding tests for:

  • Maximum font size limit
  • Minimum font size limit
  • Font size calculation with special characters
packages/chat/app/context/TextContext.tsx (1)

19-19: 🧹 Nitpick (assertive)

Make autosave delay configurable.

Consider moving AUTOSAVE_DELAY to environment configuration.

.github/workflows/expo-test.yml (1)

1-31: 🧹 Nitpick (assertive)

Fix YAML formatting issues.

The workflow logic is correct, but there are formatting inconsistencies.

-    branches: [ main ]
+    branches: [main]
-    - uses: actions/checkout@v4
+      - uses: actions/checkout@v4
-    
+
-      
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 5-5: too many spaces inside brackets

(brackets)


[error] 5-5: too many spaces inside brackets

(brackets)


[error] 7-7: too many spaces inside brackets

(brackets)


[error] 7-7: too many spaces inside brackets

(brackets)


[error] 17-17: wrong indentation: expected 6 but found 4

(indentation)


[error] 18-18: trailing spaces

(trailing-spaces)


[error] 28-28: trailing spaces

(trailing-spaces)

packages/chat/app/__tests__/storage.test.ts (1)

1-7: ⚠️ Potential issue

Fix AsyncStorage setup in test environment.

The pipeline is failing due to AsyncStorage not being properly initialized in the test environment.

Add a mock for AsyncStorage in your test setup:

+jest.mock('@react-native-async-storage/async-storage', () => ({
+  clear: jest.fn(),
+  getItem: jest.fn(),
+  setItem: jest.fn(),
+}));
🧰 Tools
🪛 GitHub Actions: Expo Tests

[error] 1-1: [@RNC/AsyncStorage]: NativeModule: AsyncStorage is null. To fix this issue try these steps: • Uninstall, rebuild and restart the app. • Run the packager with --reset-cache flag. • If you are using CocoaPods on iOS, run pod install in the ios directory, then rebuild and re-run the app.

packages/chat/README.md (1)

1-62: 🧹 Nitpick (assertive)

Fix markdown formatting issues.

The README has several formatting issues:

  • Add language identifier to code blocks
  • Remove trailing spaces
  • Add blank lines around code blocks
-```
+```bash
 app/
  ├─ __tests__/
🧰 Tools
🪛 LanguageTool

[style] ~58-~58: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ...sx ├─ help.tsx └─ settings.tsx ``` Feel free to contribute! Open issues for bugs or fea...

(FEEL_FREE_TO_STYLE_ME)


[style] ~61-~61: Using many exclamation marks might seem excessive (in this case: 4 exclamation marks for a text that’s 1893 characters long)
Context: ...t with your enhancements! Happy coding! 🎉

(EN_EXCESSIVE_EXCLAMATION)

🪛 markdownlint-cli2 (0.17.2)

5-5: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


14-14: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


16-16: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


32-32: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


46-46: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


59-59: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)

🛑 Comments failed to post (42)
packages/chat/app/_layout.tsx (2)

43-49: 🧹 Nitpick (assertive)

Top-level error boundary is a good practice.
Wrapping the app in an ErrorBoundary ensures errors are caught globally. Consider integrating a remote error-tracking tool like Sentry if you need production-level monitoring.


11-29: 🧹 Nitpick (assertive)

Consider removing the extra fragment.
Wrapping <WelcomeModal /> and <Stack /> inside <>...</> isn't strictly needed. This is a minor code simplification suggestion.

-        <>
           <WelcomeModal />
           <Stack
-        </>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

function AppContent() {
  const { currentTheme } = useSettings();
  
  return (
    <PaperProvider theme={currentTheme}>
      <TextProvider>
          <WelcomeModal />
          <Stack 
            screenOptions={{ 
              headerShown: false,
              contentStyle: { flex: 1 }
            }} 
          />
      </TextProvider>
    </PaperProvider>
  );
}
packages/chat/app/components/ErrorBoundary.tsx (2)

14-42: 🧹 Nitpick (assertive)

Error boundary is correctly implemented.
Storing errors in state and logging is standard. Consider optionally integrating a remote logging service.


44-73: 🧹 Nitpick (assertive)

Friendly fallback UI.
Displaying a “Try Again” button is user-friendly. Ensure sensitive error messages are not exposed in production.

packages/chat/app/utils/storageUtils.ts (4)

33-37: 🧹 Nitpick (assertive)

Rename for clarity if desired.

The interface provides clean structure for pagination and search options. You might consider a more explicit name like MessagesQueryOptions to better convey its purpose.


49-49: 🧹 Nitpick (assertive)

Consider type-checking after JSON parse.

let messages = jsonValue ? JSON.parse(jsonValue) : []; could benefit from basic type validation, especially if user data might become corrupted.


51-57: 🧹 Nitpick (assertive)

Potential performance strain with large datasets.

Filtering all messages on each call can be costly for large storage. If performance becomes an issue, consider indexing or a more efficient query mechanism.


39-45: 💡 Verification agent

🧩 Analysis chain

Ensure old calls are updated to new signature.

Switching to an object parameter is a great improvement. However, verify all call sites that previously used (page, pageSize) are updated to use the new options object.


🏁 Script executed:

#!/bin/bash
# Checking for references to old function signature usage
rg --context 3 "getMessages\(.*[0-9]+.*\,.*[0-9]+" 

Length of output: 175


Let's run this script to verify whether there are still any call sites using the old API signature.


🏁 Script executed:

#!/bin/bash
# Searching for references to old function signature usage (numeric parameters) in the codebase
rg --context 3 "getMessages\s*\(\s*\d+\s*,\s*\d+"

Length of output: 598


Update call sites for getMessages signature

  • The legacy call using numeric parameters exists in packages/chat/app/context/TextContext.tsx (e.g., await getMessages(0, 1)), which still needs to be updated to use the new options object.
packages/chat/app/components/BigTextDisplay.tsx (3)

28-31: 🧹 Nitpick (assertive)

Fallback logic clarity.

Using propMaxFontSize ?? (startingFontSize / 2.4) is neat. Ensure the ratio (2.4 here) is documented or explained to avoid confusion.


99-129: 🧹 Nitpick (assertive)

Keyboard handlers need type definitions.

handleKeyboardShow(e: any) handles an event object. Consider a typed approach or validating e.endCoordinates?.height to reduce runtime errors.


179-192: 🧹 Nitpick (assertive)

Dimension change logic is well designed.

Double-check quickly that it’s not triggered too frequently on some Android devices with ephemeral orientation changes. Debounce usage might handle that already.

packages/chat/app/settings.tsx (1)

186-194: 🧹 Nitpick (assertive)

Reset button clarity.

Distinguishing it with a bold color properly signals its destructive action. Confirm there's no need for a secondary confirmation.

packages/chat/app/history.tsx (1)

143-147: 🧹 Nitpick (assertive)

Refactor string concatenation to template literals.
Use template literals for readability and consistency.

- "Yesterday " +
- date.toLocaleTimeString(undefined, {
-   hour: "2-digit",
-   minute: "2-digit",
- })
+ `Yesterday ${date.toLocaleTimeString(undefined, {
+   hour: "2-digit",
+   minute: "2-digit",
+ })}`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                `Yesterday ${date.toLocaleTimeString(undefined, {
                    hour: "2-digit",
                    minute: "2-digit",
                })}`
🧰 Tools
🪛 Biome (1.9.4)

[error] 143-147: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

packages/chat/app/utils/registerServiceWorker.ts (1)

5-8: 🧹 Nitpick (assertive)

Enhance error handling and logging.

Consider using a proper logging service for production and improving error handling.

-      console.log('SW registered:', registration);
+      // Use a proper logging service
+      if (process.env.NODE_ENV !== 'production') {
+        console.log('SW registered:', registration);
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      // Use a proper logging service
      if (process.env.NODE_ENV !== 'production') {
        console.log('SW registered:', registration);
      }
    } catch (error) {
      console.log('SW registration failed:', error);
    }
packages/chat/app/index.tsx (1)

6-17: 🧹 Nitpick (assertive)

Consider optimizing service worker initialization.

The implementation works but could be more efficient.

   useEffect(() => {
     if (Platform.OS === 'web' && typeof window !== 'undefined') {
-      const initServiceWorker = () => {
-        import('./utils/registerServiceWorker')
-          .then(({ registerServiceWorker }) => registerServiceWorker())
-          .catch(error => console.error('Failed to load SW registration:', error));
-      };
+      const initServiceWorker = async () => {
+        try {
+          const { registerServiceWorker } = await import('./utils/registerServiceWorker');
+          await registerServiceWorker();
+        } catch (error) {
+          // Handle error appropriately
+        }
+      };

       window.addEventListener('load', initServiceWorker);
       return () => window.removeEventListener('load', initServiceWorker);
     }
   }, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  useEffect(() => {
    if (Platform.OS === 'web' && typeof window !== 'undefined') {
      const initServiceWorker = async () => {
        try {
          const { registerServiceWorker } = await import('./utils/registerServiceWorker');
          await registerServiceWorker();
        } catch (error) {
          // Handle error appropriately
        }
      };

      window.addEventListener('load', initServiceWorker);
      return () => window.removeEventListener('load', initServiceWorker);
    }
  }, []);
packages/chat/app/utils/settingsStorage.ts (2)

14-20: 🧹 Nitpick (assertive)

Add type safety to settings object.

Consider using a more specific type than Record<string, unknown>.

+interface Settings {
+  version: number;
+  // Add other settings properties
+}
-export async function saveSettings(settings: Record<string, unknown>): Promise<void> {
+export async function saveSettings(settings: Settings): Promise<void> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

interface Settings {
  version: number;
  // Add other settings properties
}

export async function saveSettings(settings: Settings): Promise<void> {
  try {
    await AsyncStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
  } catch (error) {
    throw new Error(`Failed to save settings: ${error}`);
  }
}

5-12: 🧹 Nitpick (assertive)

Add validation and versioning to settings.

Consider adding schema validation and versioning for better maintainability.

+const SETTINGS_VERSION = 1;
+
 export async function loadSettings(): Promise<Record<string, unknown> | null> {
   try {
     const settingsJson = await AsyncStorage.getItem(SETTINGS_STORAGE_KEY);
-    return settingsJson ? JSON.parse(settingsJson) : null;
+    if (!settingsJson) return null;
+    const settings = JSON.parse(settingsJson);
+    if (settings.version !== SETTINGS_VERSION) {
+      // Handle migration
+    }
+    return settings;
   } catch (error) {
     throw new Error(`Failed to load settings: ${error}`);
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const SETTINGS_VERSION = 1;

export async function loadSettings(): Promise<Record<string, unknown> | null> {
  try {
    const settingsJson = await AsyncStorage.getItem(SETTINGS_STORAGE_KEY);
    if (!settingsJson) return null;
    const settings = JSON.parse(settingsJson);
    if (settings.version !== SETTINGS_VERSION) {
      // Handle migration
    }
    return settings;
  } catch (error) {
    throw new Error(`Failed to load settings: ${error}`);
  }
}
packages/chat/app/components/InstallPWA.tsx (2)

41-44: 🧹 Nitpick (assertive)

Enhance error handling with user feedback.

Consider providing user feedback when installation fails.

     } catch (error) {
       console.error('Installation failed:', error);
+      // Consider showing a user-friendly error message
+      Alert.alert('Installation failed', 'Please try again later');
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    } catch (error) {
      console.error('Installation failed:', error);
      // Consider showing a user-friendly error message
      Alert.alert('Installation failed', 'Please try again later');
    }
    setDeferredPrompt(null);

15-29: 🧹 Nitpick (assertive)

Consider moving platform check to component level.

Move the platform check to the component level to avoid unnecessary effect setup.

 export function InstallPWA() {
+  if (Platform.OS !== 'web') return null;
+
   const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null);
   const [isInstallable, setIsInstallable] = useState(false);

   useEffect(() => {
-    if (Platform.OS !== 'web') return;
-
     const handleBeforeInstallPrompt = (e: Event) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export function InstallPWA() {
  if (Platform.OS !== 'web') return null;

  const [deferredPrompt, setDeferredPrompt] =
    useState<BeforeInstallPromptEvent | null>(null);
  const [isInstallable, setIsInstallable] = useState(false);

  useEffect(() => {
    const handleBeforeInstallPrompt = (e: Event) => {
      e.preventDefault();
      setDeferredPrompt(e as BeforeInstallPromptEvent);
      setIsInstallable(true);
    };

    window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);

    return () => {
      window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
    };
  }, []);

  // ...rest of the component's implementation
}
packages/chat/app/components/BottomBar.tsx (1)

18-26: 🧹 Nitpick (assertive)

Move styles outside component.

StyleSheet.create is being called on every render. Move it outside the component.

+const styles = StyleSheet.create({
+  container: {
+    flexDirection: 'row',
+    justifyContent: 'space-around',
+    alignItems: 'center',
+    height: 60,
+  },
+});

 export default function BottomBar({ onClearPress, onHistoryPress }: BottomBarProps) {
   const theme = useTheme();
   const { width } = useWindowDimensions();
-
-  const styles = StyleSheet.create({
-    container: {
-      flexDirection: 'row',
-      justifyContent: 'space-around',
-      alignItems: 'center',
-      height: 60,
-      backgroundColor: theme.colors.background,
-    },
-  });
+
+  const containerStyle = [styles.container, { backgroundColor: theme.colors.background }];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

// Moved outside the component to avoid recreating the static styles on every render.
const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    alignItems: 'center',
    height: 60,
  },
});

export default function BottomBar({ onClearPress, onHistoryPress }: BottomBarProps) {
  const theme = useTheme();
  const { width } = useWindowDimensions();

  // Merge the static style with the dynamic backgroundColor based on the theme.
  const containerStyle = [styles.container, { backgroundColor: theme.colors.background }];

  // ...rest of the component logic
}
packages/chat/app/__tests__/HistoryScreen.test.tsx (1)

7-13: 🧹 Nitpick (assertive)

Simplify Alert mock.

The Alert mock can be simplified using jest.fn().

 jest.mock('react-native', () => ({
   ...jest.requireActual('react-native'),
-  Alert: {
-    ...jest.requireActual('react-native').Alert,
-    alert: jest.fn()
-  }
+  Alert: { alert: jest.fn() }
 }));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

jest.mock('react-native', () => ({
  ...jest.requireActual('react-native'),
  Alert: { alert: jest.fn() }
}));
🧰 Tools
🪛 GitHub Actions: Expo Tests

[error] 7-7: Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'SettingsManager' could not be found. Verify that a module by this name is registered in the native binary.

packages/chat/app/__tests__/accessibility.test.tsx (1)

46-56: 🧹 Nitpick (assertive)

Add cleanup for AccessibilityInfo mock.

Restore the original AccessibilityInfo.announceForAccessibility after test.

   describe('Screen reader announcements', () => {
     it('announces errors', () => {
       const mockAnnounce = jest.spyOn(AccessibilityInfo, 'announceForAccessibility');
+      
+      afterEach(() => {
+        mockAnnounce.mockRestore();
+      });
+      
       const { rerender } = render(<HomeScreen />);
       
       // Simulate an error
       rerender(<HomeScreen error="Test error" />);
       
       expect(mockAnnounce).toHaveBeenCalledWith('Test error');
     });
   });

Committable suggestion skipped: line range outside the PR's diff.

packages/chat/app/+html.tsx (2)

26-26: 🛠️ Refactor suggestion

Move service worker registration to a separate file.

Using dangerouslySetInnerHTML poses security risks. Consider moving the service worker registration code to a separate file.

-                <script dangerouslySetInnerHTML={{ __html: sw }} />
+                <script src="/js/register-sw.js" defer />

Also applies to: 41-51

🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


18-21: 🧹 Nitpick (assertive)

Use self-closing tag for script element.

-                <script
-                    src="https://tinylytics.app/embed/ezMr4h65sCPevsfzK4ed.js"
-                    defer
-                ></script>
+                <script
+                    src="https://tinylytics.app/embed/ezMr4h65sCPevsfzK4ed.js"
+                    defer
+                />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                <script
                    src="https://tinylytics.app/embed/ezMr4h65sCPevsfzK4ed.js"
                    defer
                />
🧰 Tools
🪛 Biome (1.9.4)

[error] 18-21: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

packages/chat/app/context/SettingsContext.tsx (2)

7-7: 🧹 Nitpick (assertive)

Consider using enum for theme types.

Using an enum would provide better type safety and autocompletion.

-export type ThemeType = 'classic' | 'ocean' | 'forest' | 'sunset' | 'mono' | 'neon' | 'contrast' | 'candy' | 'mint';
+export enum ThemeType {
+  Classic = 'classic',
+  Ocean = 'ocean',
+  Forest = 'forest',
+  Sunset = 'sunset',
+  Mono = 'mono',
+  Neon = 'neon',
+  Contrast = 'contrast',
+  Candy = 'candy',
+  Mint = 'mint'
+}

Also applies to: 33-33


55-59: 🛠️ Refactor suggestion

Add error handling for settings update.

The updateSettings function should handle potential storage failures.

   const updateSettings = async (newSettings: Partial<Settings>) => {
     const updatedSettings = { ...settings, ...newSettings };
     setSettings(updatedSettings);
-    await saveSettings(updatedSettings);
+    try {
+      await saveSettings(updatedSettings);
+    } catch (err) {
+      console.error('Failed to save settings:', err);
+      setSettings(settings); // Revert on failure
+    }
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  const updateSettings = async (newSettings: Partial<Settings>) => {
    const updatedSettings = { ...settings, ...newSettings };
    setSettings(updatedSettings);
    try {
      await saveSettings(updatedSettings);
    } catch (err) {
      console.error('Failed to save settings:', err);
      setSettings(settings); // Revert on failure
    }
  };
packages/chat/app/about.tsx (2)

12-14: 🛠️ Refactor suggestion

Use encodeURIComponent for Wikipedia URLs.

Ensure URLs are properly encoded to handle special characters in names.

-        Linking.openURL(`https://en.wikipedia.org/wiki/${name}`).catch((err) =>
+        Linking.openURL(`https://en.wikipedia.org/wiki/${encodeURIComponent(name)}`).catch((err) =>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        Linking.openURL(`https://en.wikipedia.org/wiki/${encodeURIComponent(name)}`).catch((err) =>
            console.error("Failed to open Wikipedia:", err),
        );

18-18: 🧹 Nitpick (assertive)

Move email address to configuration.

Hardcoded email addresses make maintenance difficult.

+const FEEDBACK_EMAIL = process.env.FEEDBACK_EMAIL || 'feedback@orbiting.com';

   const handleEmailPress = () => {
-    Linking.openURL("mailto:feedback@orbiting.com");
+    Linking.openURL(`mailto:${FEEDBACK_EMAIL}`);
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const FEEDBACK_EMAIL = process.env.FEEDBACK_EMAIL || 'feedback@orbiting.com';

const handleEmailPress = () => {
  Linking.openURL(`mailto:${FEEDBACK_EMAIL}`);
};
packages/chat/app/components/PageLayout.tsx (1)

16-21: 🧹 Nitpick (assertive)

Enhance error display with retry option.

Add a retry button and improve error message presentation.

             return (
                 <View style={styles.errorContainer}>
-                    <Text>Something went wrong</Text>
-                    <Text>{this.state.error?.message}</Text>
+                    <Text variant="headlineSmall">Oops! Something went wrong</Text>
+                    <Text style={styles.errorMessage}>{this.state.error?.message}</Text>
+                    <Button onPress={() => this.setState({ hasError: false })}>
+                        Try Again
+                    </Button>
                 </View>
             );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

            return (
                <View style={styles.errorContainer}>
                    <Text variant="headlineSmall">Oops! Something went wrong</Text>
                    <Text style={styles.errorMessage}>{this.state.error?.message}</Text>
                    <Button onPress={() => this.setState({ hasError: false })}>
                        Try Again
                    </Button>
                </View>
            );
packages/chat/app/components/WelcomeModal.tsx (3)

34-36: 🛠️ Refactor suggestion

Move email address to configuration.

Hardcoded email should be moved to a configuration file.


90-90: 🛠️ Refactor suggestion

Remove type assertions using proper typing.

The as any assertions can be replaced with proper types.

-contentContainerStyle={styles.modalContainer as any}
+contentContainerStyle={styles.modalContainer}

Also applies to: 91-91, 92-92


13-25: 🧹 Nitpick (assertive)

Improve cookie handling with error boundaries.

Consider using a try-catch wrapper utility for cookie operations.

+const getCookie = (name: string) => {
+  try {
+    return Cookies.get(name);
+  } catch (error) {
+    console.error(`Cookie error: ${error}`);
+    return null;
+  }
+};

 useEffect(() => {
   if (Platform.OS === "web") {
-    try {
-      const hasSeenWelcome = Cookies.get(WELCOME_COOKIE);
-      if (!hasSeenWelcome) {
-        setVisible(true);
-      }
-    } catch (error) {
-      console.error("Failed to check welcome cookie:", error);
-      setVisible(true);
-    }
+    const hasSeenWelcome = getCookie(WELCOME_COOKIE);
+    if (!hasSeenWelcome) {
+      setVisible(true);
+    }
   }
 }, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const getCookie = (name: string) => {
  try {
    return Cookies.get(name);
  } catch (error) {
    console.error(`Cookie error: ${error}`);
    return null;
  }
};

useEffect(() => {
  if (Platform.OS === "web") {
    const hasSeenWelcome = getCookie(WELCOME_COOKIE);
    if (!hasSeenWelcome) {
      setVisible(true);
    }
  }
}, []);
packages/chat/app/components/HomeScreen.tsx (2)

70-87: 🧹 Nitpick (assertive)

Optimize shake gesture handling.

Consider debouncing the shake handler to prevent rapid consecutive triggers.


74-84: 🧹 Nitpick (assertive)

Extract animation duration constants.

Move magic numbers to named constants.

+const FLASH_IN_DURATION = 100;
+const FLASH_OUT_DURATION = 900;

 Animated.sequence([
   Animated.timing(flashAnim, {
     toValue: 1,
-    duration: 100,
+    duration: FLASH_IN_DURATION,
     useNativeDriver: false,
   }),
   Animated.timing(flashAnim, {
     toValue: 0,
-    duration: 900,
+    duration: FLASH_OUT_DURATION,
     useNativeDriver: false,
   })
 ])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

+const FLASH_IN_DURATION = 100;
+const FLASH_OUT_DURATION = 900;

            Animated.sequence([
                Animated.timing(flashAnim, {
                    toValue: 1,
                    duration: FLASH_IN_DURATION,
                    useNativeDriver: false,
                }),
                Animated.timing(flashAnim, {
                    toValue: 0,
                    duration: FLASH_OUT_DURATION,
                    useNativeDriver: false,
                })
packages/chat/app/context/TextContext.tsx (1)

67-72: 🧹 Nitpick (assertive)

Centralize error messages.

Move error messages to a separate constants file for better maintenance.

+// errorMessages.ts
+export const ERROR_MESSAGES = {
+  AUTOSAVE_FAILED: 'Autosave failed:',
+  TEXT_UPDATE_FAILED: 'Failed to update text:',
+  CLEAR_TEXT_FAILED: 'Failed to clear text:',
+};

Committable suggestion skipped: line range outside the PR's diff.

packages/chat/app/themes/index.ts (2)

338-399: 🛠️ Refactor suggestion

Adjust neon theme colors for better readability.

Green text (#00cc00) on white background might be difficult to read.

-        onBackground: '#00cc00',
+        onBackground: '#008000',
-        onSurface: '#00cc00',
+        onSurface: '#008000',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    light: {
      colors: {
        primary: '#00e600',
        onPrimary: '#000000',
        primaryContainer: '#e6ffe6',
        onPrimaryContainer: '#003300',
        secondary: '#e600e6',
        onSecondary: '#000000',
        secondaryContainer: '#ffe6ff',
        onSecondaryContainer: '#330033',
        background: '#ffffff',
        onBackground: '#008000',
        surface: '#ffffff',
        onSurface: '#008000',
        surfaceVariant: '#e6ffe6',
        onSurfaceVariant: '#003300',
        outline: '#00ff00',
        elevation: {
          level0: 'transparent',
          level1: '#e6ffe6',
          level2: '#ccffcc',
          level3: '#b3ffb3',
          level4: '#99ff99',
          level5: '#80ff80',
        }
      },
      custom: {
        tabBar: '#e6ffe6',
        tabBarActive: '#00ff00',
      }
    },
    dark: {
      colors: {
        primary: '#00e600',
        onPrimary: '#000000',
        primaryContainer: '#001a00',
        onPrimaryContainer: '#00ff00',
        secondary: '#e600e6',
        onSecondary: '#000000',
        secondaryContainer: '#1a001a',
        onSecondaryContainer: '#ff00ff',
        background: '#000000',
        onBackground: '#00ff00',
        surface: '#000000',
        onSurface: '#00ff00',
        surfaceVariant: '#001a00',
        onSurfaceVariant: '#00ff00',
        outline: '#00ff00',
        elevation: {
          level0: 'transparent',
          level1: '#001a00',
          level2: '#003300',
          level3: '#004d00',
          level4: '#006600',
          level5: '#008000',
        }
      },
      custom: {
        tabBar: '#001a00',
        tabBarActive: '#00ff00',
      }
    }

4-14: 💡 Verification agent

🧩 Analysis chain

Verify color contrast ratios for accessibility.

Some theme combinations might not meet WCAG contrast requirements.


🌐 Web query:

What are the minimum color contrast requirements for WCAG 2.1 Level AA compliance?

💡 Result:

WCAG 2.1 Level AA compliance requires specific color contrast ratios to ensure accessibility for users with visual impairments:

Normal Text Contrast

  • Minimum 4.5:1 contrast ratio between text/background colors[1][2][5][7]
  • Applies to standard-sized text (under 18pt regular or 14pt bold)[4][7]
  • Includes images containing text[1][5]

Large Text Contrast

  • Minimum 3:1 contrast ratio for:
    • Text ≥18pt regular
    • Text ≥14pt bold[1][2][4][5]

Additional Requirements in WCAG 2.1

  • Non-text elements like UI components/icons require 3:1 contrast[1][2]
  • Applies to:
    • Form input borders
    • Graphical objects essential to understanding content[1][2]

Exceptions

  • Logos/brand names[1][5]
  • Decorative/inactive UI elements[1][2]
  • Text in images containing significant other visual content[1]

Ratios must be precise – no rounding up (e.g., 4.47:1 fails)[1]. Tools like WebAIM's Contrast Checker[4] or Accessible Web's tool[8] can verify compliance using hex color codes.

These standards help ensure content remains readable for users with low vision or color deficiencies while maintaining design flexibility[5][7].

Citations:


Accessibility Contrast Issues in Theme Definitions

  • Neon Theme: The combination of #00ff00 (primary) and #ff00ff (secondary) has an estimated contrast ratio around 2.3:1—well below the WCAG 2.1 Level AA minimum of 4.5:1 for normal text.
  • Candy Theme: The pairing of #ff1493 and #9932cc results in an estimated ratio near 1.6:1, which is far insufficient.
  • Classic Theme: The #000000/#666666 combo yields roughly 3.66:1, below the required threshold.
  • Sunset, Forest, Ocean, and Mint Themes: Preliminary calculations indicate these themes also offer contrast ratios between approximately 2.7:1 and 3.3:1—again falling short of the 4.5:1 guideline.

In contrast, the Mono (#000000/#ffffff) and Contrast (#ffff00/#000000) themes already exceed the minimum contrast ratio. Consider revisiting the color choices for the other themes to achieve at least a 4.5:1 ratio for normal text (or use them only where large text is applied, which requires a minimum of 3:1).

wrangler.toml (1)

14-15: 💡 Verification agent

🧩 Analysis chain

Verify Node.js LTS compatibility.

Check if Node.js 20 is the current LTS version.


🌐 Web query:

What is the current LTS version of Node.js?

💡 Result:

The current Long Term Support (LTS) version of Node.js as of February 2025 is Node.js v22.x (codename "Jod")[1][3][4][7]. This version transitioned to Active LTS status on October 29, 2024[1][7], and will receive critical updates through its support lifecycle:

Support Phase Timeline
Active LTS Until October 2025[1][8]
Maintenance LTS Until April 2027[1][7][8]

Key details:

  • Replaces Node.js v20.x (now in maintenance mode)[1]
  • Introduces features like a built-in WebSocket client[1]
  • Default version for major platforms like Netlify since February 2025[3]
  • Recommended for production environments due to extended security patches and stability guarantees[1][8]

The next LTS release will be Node.js v24.x, scheduled for October 2025[7]. Developers should prioritize upgrading to v22.x for applications requiring long-term stability and security updates.

Citations:


Action: Update Node.js version for LTS compatibility.

  • The current LTS as of February 2025 is Node.js v22.x.
  • Change NODE_VERSION in wrangler.toml (lines 14-15) from "20" to "22".
.github/workflows/firebase-hosting-pull-request.yml (1)

16-16: 🛠️ Refactor suggestion

Update actions/setup-node to v4.

The current version is outdated.

-              uses: actions/setup-node@v3
+              uses: actions/setup-node@v4
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

              uses: actions/setup-node@v4
🧰 Tools
🪛 actionlint (1.7.4)

16-16: the runner of "actions/setup-node@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

.github/workflows/firebase-hosting-merge.yml (2)

18-18: ⚠️ Potential issue

Update setup-node action version.

The current version is outdated.

-uses: actions/setup-node@v3
+uses: actions/setup-node@v4
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

              uses: actions/setup-node@v4
🧰 Tools
🪛 actionlint (1.7.4)

18-18: the runner of "actions/setup-node@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


21-21: ⚠️ Potential issue

Update Node.js version to a stable release.

Node.js v22 is not yet released. Use a stable LTS version.

-node-version: "22"
+node-version: "20"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                  node-version: "20"
packages/chat/package.json (1)

85-91: 🧹 Nitpick (assertive)

Consider using TypeScript ESLint.

Since you're using TypeScript, add @typescript-eslint for better type checking.

 "devDependencies": {
+  "@typescript-eslint/eslint-plugin": "^7.0.0",
+  "@typescript-eslint/parser": "^7.0.0",
   "eslint": "^8.57.0",
   "eslint-config-expo": "~8.0.1"
 }

@harperreed harperreed merged commit 0fd533b into expo-cleanup Feb 12, 2025
6 of 8 checks passed
@harperreed harperreed deleted the linting branch February 12, 2025 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant