sourabhrealtime
Version:
ROBUST RICH TEXT EDITOR: Single-pane contentEditable with direct text selection formatting, speech features, undo/redo, professional UI - Perfect TipTap alternative
292 lines (265 loc) • 9.21 kB
JavaScript
// Simple Supabase API with automatic table creation
const SUPABASE_URL = "https://supabase.merai.app";
const SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q";
const simpleSupabase = {
async init() {
try {
// Create projects table
await fetch(`${SUPABASE_URL}/rest/v1/rpc/exec_sql`, {
method: 'POST',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sql: `
CREATE TABLE IF NOT EXISTS projects (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
content TEXT DEFAULT '<p>Start typing...</p>',
created_by UUID NOT NULL,
updated_by UUID,
members TEXT[] DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS approval_requests (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
project_id UUID NOT NULL,
project_name VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
user_id UUID NOT NULL,
user_name VARCHAR(255) NOT NULL,
user_email VARCHAR(255) NOT NULL,
status VARCHAR(20) DEFAULT 'pending',
reviewed_by UUID,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
reviewed_at TIMESTAMP WITH TIME ZONE
);
`
})
});
} catch (error) {
// Tables may already exist
}
},
async authenticateUser(email, password) {
try {
await this.init();
const response = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=password`, {
method: 'POST',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
if (response.ok) {
const data = await response.json();
return {
success: true,
user: {
id: data.user.id,
email: data.user.email,
name: data.user.user_metadata?.name || data.user.email.split('@')[0],
role: data.user.user_metadata?.role || 'user'
},
token: data.access_token
};
}
return { success: false, message: 'Invalid credentials' };
} catch (error) {
return { success: false, message: 'Authentication failed' };
}
},
async getProjects(userId, userRole) {
try {
await this.init();
const response = await fetch(`${SUPABASE_URL}/rest/v1/projects?select=*`, {
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const projects = await response.json();
return { success: true, projects };
}
return { success: true, projects: [] };
} catch (error) {
return { success: true, projects: [] };
}
},
async createProject(projectData, creatorId) {
try {
await this.init();
const response = await fetch(`${SUPABASE_URL}/rest/v1/projects`, {
method: 'POST',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json',
'Prefer': 'return=representation'
},
body: JSON.stringify({
name: projectData.name,
description: projectData.description || '',
content: '<p>Start typing...</p>',
created_by: creatorId,
members: [creatorId],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
})
});
if (response.ok) {
const projects = await response.json();
const project = Array.isArray(projects) ? projects[0] : projects;
return { success: true, project };
}
return { success: false, message: 'Failed to create project' };
} catch (error) {
return { success: false, message: error.message };
}
},
async updateProjectContent(projectId, content, userId) {
try {
const response = await fetch(`${SUPABASE_URL}/rest/v1/projects?id=eq.${projectId}`, {
method: 'PATCH',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
content,
updated_at: new Date().toISOString(),
updated_by: userId
})
});
return { success: response.ok };
} catch (error) {
return { success: false };
}
},
async getApprovalRequests() {
try {
await this.init();
const response = await fetch(`${SUPABASE_URL}/rest/v1/approval_requests?status=eq.pending&select=*`, {
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const requests = await response.json();
return { success: true, requests };
}
return { success: true, requests: [] };
} catch (error) {
return { success: true, requests: [] };
}
},
async createApprovalRequest(requestData) {
try {
await this.init();
const response = await fetch(`${SUPABASE_URL}/rest/v1/approval_requests`, {
method: 'POST',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json',
'Prefer': 'return=representation'
},
body: JSON.stringify({
project_id: requestData.projectId,
project_name: requestData.projectName,
content: requestData.content,
user_id: requestData.user.id,
user_name: requestData.user.name,
user_email: requestData.user.email,
status: 'pending',
created_at: new Date().toISOString()
})
});
if (response.ok) {
const requests = await response.json();
const request = Array.isArray(requests) ? requests[0] : requests;
return { success: true, request };
}
return { success: false, message: 'Failed to create approval request' };
} catch (error) {
return { success: false, message: error.message };
}
},
async updateApprovalRequest(requestId, status, adminId) {
try {
const response = await fetch(`${SUPABASE_URL}/rest/v1/approval_requests?id=eq.${requestId}`, {
method: 'PATCH',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
status,
reviewed_by: adminId,
reviewed_at: new Date().toISOString()
})
});
return { success: response.ok };
} catch (error) {
return { success: false };
}
},
async getAllUsers() {
try {
const response = await fetch(`${SUPABASE_URL}/auth/v1/admin/users`, {
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const data = await response.json();
const users = data.users?.map(user => ({
id: user.id,
email: user.email,
name: user.user_metadata?.name || user.email.split('@')[0],
role: user.user_metadata?.role || 'user',
created_at: user.created_at
})) || [];
return { success: true, users };
}
return { success: true, users: [] };
} catch (error) {
return { success: true, users: [] };
}
},
async inviteUserToProject(projectId, userId, invitedBy) {
try {
await this.init();
// Add user to project members
const projectResponse = await fetch(`${SUPABASE_URL}/rest/v1/projects?id=eq.${projectId}`, {
method: 'PATCH',
headers: {
'apikey': SERVICE_ROLE_KEY,
'Authorization': `Bearer ${SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
members: `{${userId}}`,
updated_at: new Date().toISOString()
})
});
return { success: projectResponse.ok };
} catch (error) {
return { success: false, message: error.message };
}
}
};
export default simpleSupabase;