Initial commit: code as received (Create/Anything export)
Insole-production time tracker exported from the Create/Anything AI platform. Baseline snapshot before any reverse-engineering or cleanup. - apps/mobile: Expo Router app (iOS/Android/web), the only workspace - publisher/: standalone OpenNext/AWS deploy tooling for the web side - Backend (/api/tasks, /api/logs + DB) lives remotely, not in this repo
This commit is contained in:
299
apps/mobile/polyfills/web/contacts.web.ts
Normal file
299
apps/mobile/polyfills/web/contacts.web.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
import type { ExistingContact, ContactQuery } from 'expo-contacts';
|
||||
import { Fields, SortTypes } from 'expo-contacts/src/Contacts';
|
||||
import Alert from './alerts.web';
|
||||
import * as Notifications from 'expo-contacts';
|
||||
const { PermissionStatus } = Notifications;
|
||||
|
||||
export { PermissionStatus, Fields, SortTypes };
|
||||
|
||||
const fakeContacts: ExistingContact[] = [
|
||||
{
|
||||
id: '1',
|
||||
contactType: 'person',
|
||||
name: 'John Doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
phoneNumbers: [
|
||||
{ number: '+1 (555) 123-4567', isPrimary: true, label: 'mobile' },
|
||||
{ number: '+1 (555) 987-6543', isPrimary: false, label: 'home' },
|
||||
],
|
||||
emails: [
|
||||
{ email: 'john.doe@example.com', isPrimary: true, label: 'work' },
|
||||
{ email: 'john.personal@gmail.com', isPrimary: false, label: 'personal' },
|
||||
],
|
||||
addresses: [
|
||||
{
|
||||
street: '123 Main St',
|
||||
city: 'New York',
|
||||
region: 'NY',
|
||||
postalCode: '10001',
|
||||
country: 'USA',
|
||||
label: 'home',
|
||||
},
|
||||
],
|
||||
birthday: { day: 15, month: 5, year: 1990 },
|
||||
note: 'Met at conference',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
contactType: 'person',
|
||||
name: 'Jane Smith',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Smith',
|
||||
phoneNumbers: [{ number: '+1 (555) 234-5678', isPrimary: true, label: 'mobile' }],
|
||||
emails: [{ email: 'jane.smith@company.com', isPrimary: true, label: 'work' }],
|
||||
addresses: [
|
||||
{
|
||||
street: '456 Oak Ave',
|
||||
city: 'Los Angeles',
|
||||
region: 'CA',
|
||||
postalCode: '90210',
|
||||
country: 'USA',
|
||||
label: 'home',
|
||||
},
|
||||
],
|
||||
birthday: { day: 3, month: 12, year: 1985 },
|
||||
note: 'College friend',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
contactType: 'person',
|
||||
name: 'Bob Johnson',
|
||||
firstName: 'Bob',
|
||||
lastName: 'Johnson',
|
||||
phoneNumbers: [{ number: '+1 (555) 345-6789', isPrimary: true, label: 'mobile' }],
|
||||
emails: [{ email: 'bob.johnson@email.com', isPrimary: true, label: 'personal' }],
|
||||
addresses: [],
|
||||
birthday: { day: 22, month: 8, year: 1992 },
|
||||
note: 'Neighbor',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
contactType: 'person',
|
||||
name: 'Alice Williams',
|
||||
firstName: 'Alice',
|
||||
lastName: 'Williams',
|
||||
phoneNumbers: [
|
||||
{ number: '+1 (555) 456-7890', isPrimary: true, label: 'mobile' },
|
||||
{ number: '+1 (555) 111-2222', isPrimary: false, label: 'work' },
|
||||
],
|
||||
emails: [{ email: 'alice.williams@startup.com', isPrimary: true, label: 'work' }],
|
||||
addresses: [
|
||||
{
|
||||
street: '789 Pine St',
|
||||
city: 'San Francisco',
|
||||
region: 'CA',
|
||||
postalCode: '94102',
|
||||
country: 'USA',
|
||||
label: 'work',
|
||||
},
|
||||
],
|
||||
birthday: { day: 10, month: 3, year: 1988 },
|
||||
note: 'Business partner',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
contactType: 'person',
|
||||
name: 'Charlie Brown',
|
||||
firstName: 'Charlie',
|
||||
lastName: 'Brown',
|
||||
phoneNumbers: [{ number: '+1 (555) 567-8901', isPrimary: true, label: 'mobile' }],
|
||||
emails: [{ email: 'charlie.brown@gmail.com', isPrimary: true, label: 'personal' }],
|
||||
addresses: [],
|
||||
birthday: { day: 18, month: 11, year: 1995 },
|
||||
note: 'Gym buddy',
|
||||
},
|
||||
];
|
||||
|
||||
let permissionStatus = {
|
||||
status: PermissionStatus.UNDETERMINED,
|
||||
expires: 'never',
|
||||
granted: false,
|
||||
canAskAgain: true,
|
||||
};
|
||||
|
||||
// since we polyfill fake contacts, we always return true
|
||||
export const isAvailableAsync = async () => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export const requestPermissionsAsync = async () => {
|
||||
if (permissionStatus.status === PermissionStatus.GRANTED) {
|
||||
return permissionStatus;
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
Alert.alert(
|
||||
'"Expo Go" Would Like to Access Your Contacts',
|
||||
'Allow Expo projects to access your contacts',
|
||||
[
|
||||
{
|
||||
text: "Don't Allow",
|
||||
onPress: () => {
|
||||
permissionStatus = {
|
||||
status: PermissionStatus.DENIED,
|
||||
expires: 'never',
|
||||
granted: false,
|
||||
canAskAgain: true,
|
||||
};
|
||||
resolve(permissionStatus);
|
||||
},
|
||||
style: 'default',
|
||||
},
|
||||
{
|
||||
text: 'Continue',
|
||||
onPress: () => {
|
||||
permissionStatus = {
|
||||
status: PermissionStatus.GRANTED,
|
||||
expires: 'never',
|
||||
granted: true,
|
||||
canAskAgain: false,
|
||||
};
|
||||
resolve(permissionStatus);
|
||||
},
|
||||
style: 'default',
|
||||
},
|
||||
]
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const getPermissionsAsync = async () => {
|
||||
return permissionStatus;
|
||||
};
|
||||
|
||||
export const getContactsAsync = async (options: ContactQuery = {}) => {
|
||||
const { sort = SortTypes.FirstName, pageSize, pageOffset } = options;
|
||||
|
||||
let contacts = [...fakeContacts];
|
||||
|
||||
if (sort === SortTypes.FirstName) {
|
||||
contacts.sort((a, b) => (a.firstName || '').localeCompare(b.firstName || ''));
|
||||
} else if (sort === SortTypes.LastName) {
|
||||
contacts.sort((a, b) => (a.lastName || '').localeCompare(b.lastName || ''));
|
||||
}
|
||||
|
||||
if (pageSize && pageOffset !== undefined) {
|
||||
const startIndex = pageOffset * pageSize;
|
||||
contacts = contacts.slice(startIndex, startIndex + pageSize);
|
||||
}
|
||||
|
||||
return {
|
||||
data: contacts,
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
total: fakeContacts.length,
|
||||
};
|
||||
};
|
||||
|
||||
export const getContactByIdAsync = async (id: string, _options: ContactQuery = {}) => {
|
||||
const contact = fakeContacts.find((c) => c.id === id);
|
||||
if (!contact) {
|
||||
throw new Error(`Contact with id ${id} not found`);
|
||||
}
|
||||
|
||||
return contact;
|
||||
};
|
||||
|
||||
export const addContactAsync = async (contact: ExistingContact) => {
|
||||
const newContact: ExistingContact = {
|
||||
id: Date.now().toString(),
|
||||
contactType: contact.contactType || 'person',
|
||||
name: contact.name || '',
|
||||
firstName: contact.firstName || '',
|
||||
lastName: contact.lastName || '',
|
||||
phoneNumbers: contact.phoneNumbers || [],
|
||||
emails: contact.emails || [],
|
||||
addresses: contact.addresses || [],
|
||||
birthday: contact.birthday,
|
||||
note: contact.note || '',
|
||||
middleName: contact.middleName,
|
||||
maidenName: contact.maidenName,
|
||||
namePrefix: contact.namePrefix,
|
||||
nameSuffix: contact.nameSuffix,
|
||||
nickname: contact.nickname,
|
||||
phoneticFirstName: contact.phoneticFirstName,
|
||||
phoneticMiddleName: contact.phoneticMiddleName,
|
||||
phoneticLastName: contact.phoneticLastName,
|
||||
company: contact.company,
|
||||
jobTitle: contact.jobTitle,
|
||||
department: contact.department,
|
||||
imageAvailable: contact.imageAvailable,
|
||||
image: contact.image,
|
||||
rawImage: contact.rawImage,
|
||||
dates: contact.dates,
|
||||
relationships: contact.relationships,
|
||||
instantMessageAddresses: contact.instantMessageAddresses,
|
||||
urlAddresses: contact.urlAddresses,
|
||||
nonGregorianBirthday: contact.nonGregorianBirthday,
|
||||
socialProfiles: contact.socialProfiles,
|
||||
isFavorite: contact.isFavorite,
|
||||
};
|
||||
|
||||
fakeContacts.push(newContact);
|
||||
Alert.alert('Success', 'Contact added successfully!');
|
||||
return newContact.id;
|
||||
};
|
||||
|
||||
export const updateContactAsync = async (contact: ExistingContact) => {
|
||||
const index = fakeContacts.findIndex((c) => c.id === contact.id);
|
||||
if (index === -1) {
|
||||
throw new Error(`Contact with id ${contact.id} not found`);
|
||||
}
|
||||
|
||||
fakeContacts[index] = { ...fakeContacts[index], ...contact };
|
||||
return contact.id;
|
||||
};
|
||||
|
||||
export const removeContactAsync = async (contactId: string) => {
|
||||
const index = fakeContacts.findIndex((c) => c.id === contactId);
|
||||
if (index === -1) {
|
||||
throw new Error(`Contact with id ${contactId} not found`);
|
||||
}
|
||||
|
||||
fakeContacts.splice(index, 1);
|
||||
setTimeout(() => {
|
||||
Alert.alert('Success', 'Contact deleted successfully!');
|
||||
}, 500);
|
||||
return contactId;
|
||||
};
|
||||
|
||||
const _createNoOpAsync = async () => {
|
||||
Alert.alert('Not supported in the builder', 'Please use the Expo Go app to test this feature');
|
||||
return { type: 'custom', data: null };
|
||||
};
|
||||
|
||||
export const presentContactPickerAsync = async () => {
|
||||
return _createNoOpAsync();
|
||||
};
|
||||
export const getGroupsAsync = async () => {
|
||||
return _createNoOpAsync();
|
||||
};
|
||||
export const createGroupAsync = async () => {
|
||||
return _createNoOpAsync();
|
||||
};
|
||||
export const removeGroupAsync = async () => {
|
||||
return _createNoOpAsync();
|
||||
};
|
||||
export const updateGroupNameAsync = async () => {
|
||||
return _createNoOpAsync();
|
||||
};
|
||||
|
||||
export default {
|
||||
Fields,
|
||||
SortTypes,
|
||||
PermissionStatus,
|
||||
isAvailableAsync,
|
||||
requestPermissionsAsync,
|
||||
getPermissionsAsync,
|
||||
getContactsAsync,
|
||||
getContactByIdAsync,
|
||||
addContactAsync,
|
||||
updateContactAsync,
|
||||
removeContactAsync,
|
||||
presentContactPickerAsync,
|
||||
getGroupsAsync,
|
||||
createGroupAsync,
|
||||
removeGroupAsync,
|
||||
updateGroupNameAsync,
|
||||
};
|
||||
Reference in New Issue
Block a user