Files
beenvoice-app/plugins/withAppIntents.js
T
soconnorandCursor 6762a9bff3 Move production to beenvoice.app with migrated accounts, refreshed auth and timer UX, and expanded invoice flows.
Official URL migration preserves sessions, shortcuts prefs, and last clock-in client; auth screens match web with legal links; time clock and invoice editor/send flows are updated for the new domain and UI patterns.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 03:40:48 -04:00

144 lines
4.3 KiB
JavaScript

// @ts-check
const {
withDangerousMod,
withXcodeProject,
IOSConfig,
} = require("@expo/config-plugins");
const fs = require("fs");
const path = require("path");
const SWIFT_FILES = [
"BeenVoiceIntentHelpers.swift",
"ClockInIntent.swift",
"ClockOutIntent.swift",
"OpenTimerIntent.swift",
"BeenVoiceShortcuts.swift",
];
const SHORTCUT_REGISTRATION = `Task {
await BeenVoiceShortcuts.updateAppShortcutParameters()
}`;
/** @type {import('@expo/config-plugins').ConfigPlugin} */
function withAppIntents(config) {
const appIntentsSource = path.join(
config._internal?.projectRoot ?? process.cwd(),
"plugins",
"app-intents",
);
config = withDangerousMod(config, [
"ios",
async (config) => {
const projectRoot = config.modRequest.projectRoot;
const platformRoot = config.modRequest.platformProjectRoot;
const projectName =
config.modRequest.projectName ??
IOSConfig.XcodeUtils.getProjectName(projectRoot);
const targetDir = path.join(platformRoot, projectName);
fs.mkdirSync(targetDir, { recursive: true });
for (const file of SWIFT_FILES) {
fs.copyFileSync(path.join(appIntentsSource, file), path.join(targetDir, file));
}
const appDelegatePath = path.join(targetDir, "AppDelegate.swift");
if (fs.existsSync(appDelegatePath)) {
let appDelegate = fs.readFileSync(appDelegatePath, "utf8");
if (!appDelegate.includes("import AppIntents")) {
appDelegate = appDelegate.replace(
"internal import Expo",
"import AppIntents\ninternal import Expo",
);
}
if (!appDelegate.includes("BeenVoiceShortcuts.updateAppShortcutParameters")) {
appDelegate = appDelegate.replace(
"return super.application(application, didFinishLaunchingWithOptions: launchOptions)",
`${SHORTCUT_REGISTRATION}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)`,
);
} else {
appDelegate = appDelegate.replace(
/if #available\(iOS 1[68]\.0, \*\) \{\s*Task \{\s*await BeenVoiceShortcuts\.updateAppShortcutParameters\(\)\s*\}\s*\}/g,
SHORTCUT_REGISTRATION,
);
}
if (!appDelegate.includes("applicationDidBecomeActive")) {
appDelegate = appDelegate.replace(
" // Linking API",
` public override func applicationDidBecomeActive(_ application: UIApplication) {
${SHORTCUT_REGISTRATION}
super.applicationDidBecomeActive(application)
}
// Linking API`,
);
}
fs.writeFileSync(appDelegatePath, appDelegate);
}
return config;
},
]);
return withXcodeProject(config, (config) => {
const project = config.modResults;
const projectRoot = config.modRequest.projectRoot;
const platformRoot = config.modRequest.platformProjectRoot;
const projectName =
config.modRequest.projectName ??
IOSConfig.XcodeUtils.getProjectName(projectRoot);
for (const file of SWIFT_FILES) {
const filepath = `${projectName}/${file}`;
const absolutePath = path.join(platformRoot, filepath);
if (!fs.existsSync(absolutePath)) continue;
const fileRef = project.pbxFileReferenceSection();
const alreadyLinked = Object.values(fileRef).some(
(entry) =>
entry &&
typeof entry === "object" &&
"path" in entry &&
(entry.path === file ||
entry.path === `${projectName}/${file}` ||
String(entry.path).endsWith(`/${file}`)),
);
if (!alreadyLinked) {
IOSConfig.XcodeUtils.addBuildSourceFileToGroup({
filepath,
groupName: projectName,
project,
verbose: true,
});
}
}
const configurations = project.pbxXCBuildConfigurationSection();
for (const key of Object.keys(configurations)) {
const buildConfig = configurations[key];
if (
typeof buildConfig !== "object" ||
!buildConfig.buildSettings ||
buildConfig.buildSettings.PRODUCT_BUNDLE_IDENTIFIER !== "com.beenvoice.app"
) {
continue;
}
buildConfig.buildSettings.EXTRACT_APP_INTENTS_METADATA = "YES";
}
return config;
});
}
module.exports = withAppIntents;