mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
Initial commit
This commit is contained in:
commit
4d53d83769
73 files changed
+37728
No files matched your search
Executable
+29
@@ -0,0 +1,29 @@
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
COPY turbo.json ./
|
||||
COPY apps/admin/package.json ./apps/admin/
|
||||
COPY packages/shared/package.json ./packages/shared/
|
||||
|
||||
# Install dependencies (only what's needed for admin)
|
||||
RUN npm install
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build shared package first
|
||||
RUN npx turbo run build --filter=@sauci/shared
|
||||
|
||||
# Build admin app with env vars
|
||||
ARG VITE_SUPABASE_URL
|
||||
ARG VITE_SUPABASE_ANON_KEY
|
||||
ENV VITE_SUPABASE_URL=$VITE_SUPABASE_URL
|
||||
ENV VITE_SUPABASE_ANON_KEY=$VITE_SUPABASE_ANON_KEY
|
||||
|
||||
RUN npx turbo run build --filter=@sauci/admin
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/apps/admin/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sauci Admin</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@sauci/admin",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.39.0",
|
||||
"ra-supabase": "^1.0.0",
|
||||
"@sauci/shared": "*",
|
||||
"react": "^18.2.0",
|
||||
"react-admin": "^4.16.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"typescript": "^5.3.0",
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
}
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
import { Admin, Resource } from "react-admin";
|
||||
import { dataProvider } from "./providers/supabaseProvider";
|
||||
import { PackList, PackEdit, PackCreate } from "./resources/packs";
|
||||
import { QuestionList, QuestionEdit, QuestionCreate } from "./resources/questions";
|
||||
import { ProfileList, ResponseList } from "./resources/users";
|
||||
import { authProvider } from "./providers/authProvider";
|
||||
|
||||
const App = () => (
|
||||
<Admin dataProvider={dataProvider} authProvider={authProvider} requireAuth>
|
||||
<Resource
|
||||
name="question_packs"
|
||||
list={PackList}
|
||||
edit={PackEdit}
|
||||
create={PackCreate}
|
||||
recordRepresentation="name"
|
||||
/>
|
||||
<Resource
|
||||
name="questions"
|
||||
list={QuestionList}
|
||||
edit={QuestionEdit}
|
||||
create={QuestionCreate}
|
||||
/>
|
||||
<Resource
|
||||
name="profiles"
|
||||
list={ProfileList}
|
||||
/>
|
||||
<Resource
|
||||
name="responses"
|
||||
list={ResponseList}
|
||||
/>
|
||||
<Resource name="couples" />
|
||||
</Admin>
|
||||
);
|
||||
|
||||
export default App;
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
export const supabaseConfig = {
|
||||
url: import.meta.env.VITE_SUPABASE_URL,
|
||||
anonKey: import.meta.env.VITE_SUPABASE_ANON_KEY,
|
||||
};
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
import { AuthProvider } from 'react-admin';
|
||||
import { supabase } from '../config';
|
||||
|
||||
export const authProvider: AuthProvider = {
|
||||
login: async ({ username, password }) => {
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email: username,
|
||||
password,
|
||||
});
|
||||
if (error) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
logout: async () => {
|
||||
await supabase.auth.signOut();
|
||||
return Promise.resolve();
|
||||
},
|
||||
checkError: async (error) => {
|
||||
if (error.status === 401 || error.status === 403) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
checkAuth: async () => {
|
||||
const session = await supabase.auth.getSession();
|
||||
return session.data.session ? Promise.resolve() : Promise.reject();
|
||||
},
|
||||
getPermissions: () => Promise.resolve(),
|
||||
};
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import { supabaseConfig } from '../config';
|
||||
|
||||
export const supabase = createClient(
|
||||
supabaseConfig.url,
|
||||
supabaseConfig.anonKey
|
||||
);
|
||||
|
||||
// Custom data provider wrapper if needed for ra-data-supabase
|
||||
import { supabaseDataProvider } from 'ra-supabase';
|
||||
|
||||
export const dataProvider = supabaseDataProvider(
|
||||
supabase,
|
||||
{
|
||||
resources: {
|
||||
question_packs: 'question_packs',
|
||||
questions: 'questions',
|
||||
profiles: 'profiles',
|
||||
couples: 'couples'
|
||||
}
|
||||
}
|
||||
);
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
import { List, Datagrid, TextField, BooleanField, EditButton, Create, SimpleForm, TextInput, BooleanInput, Edit } from 'react-admin';
|
||||
|
||||
export const PackList = () => (
|
||||
<List>
|
||||
<Datagrid rowClick="edit">
|
||||
<TextField source="name" />
|
||||
<TextField source="description" />
|
||||
<BooleanField source="is_premium" />
|
||||
<BooleanField source="is_public" />
|
||||
<EditButton />
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
|
||||
export const PackEdit = () => (
|
||||
<Edit>
|
||||
<SimpleForm>
|
||||
<TextInput source="name" />
|
||||
<TextInput source="description" multiline />
|
||||
<TextInput source="icon" />
|
||||
<BooleanInput source="is_premium" />
|
||||
<BooleanInput source="is_public" />
|
||||
<TextInput source="sort_order" />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
|
||||
export const PackCreate = () => (
|
||||
<Create>
|
||||
<SimpleForm>
|
||||
<TextInput source="name" />
|
||||
<TextInput source="description" multiline />
|
||||
<TextInput source="icon" />
|
||||
<BooleanInput source="is_premium" />
|
||||
<BooleanInput source="is_public" />
|
||||
<TextInput source="sort_order" />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
import { List, Datagrid, TextField, ReferenceField, NumberField, EditButton, Create, SimpleForm, TextInput, NumberInput, ReferenceInput, SelectInput, Edit } from 'react-admin';
|
||||
|
||||
export const QuestionList = () => (
|
||||
<List>
|
||||
<Datagrid rowClick="edit">
|
||||
<TextField source="text" />
|
||||
<ReferenceField source="pack_id" reference="question_packs">
|
||||
<TextField source="name" />
|
||||
</ReferenceField>
|
||||
<NumberField source="intensity" />
|
||||
<EditButton />
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
|
||||
export const QuestionEdit = () => (
|
||||
<Edit>
|
||||
<SimpleForm>
|
||||
<ReferenceInput source="pack_id" reference="question_packs">
|
||||
<SelectInput optionText="name" />
|
||||
</ReferenceInput>
|
||||
<TextInput source="text" multiline fullWidth />
|
||||
<NumberInput source="intensity" min={1} max={5} />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
|
||||
export const QuestionCreate = () => (
|
||||
<Create>
|
||||
<SimpleForm>
|
||||
<ReferenceInput source="pack_id" reference="question_packs">
|
||||
<SelectInput optionText="name" />
|
||||
</ReferenceInput>
|
||||
<TextInput source="text" multiline fullWidth />
|
||||
<NumberInput source="intensity" min={1} max={5} />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
import { List, Datagrid, TextField, BooleanField, DateField, ReferenceField } from 'react-admin';
|
||||
|
||||
export const ProfileList = () => (
|
||||
<List>
|
||||
<Datagrid>
|
||||
<TextField source="name" />
|
||||
<TextField source="email" />
|
||||
<BooleanField source="is_premium" />
|
||||
<ReferenceField source="couple_id" reference="couples">
|
||||
<TextField source="id" />
|
||||
</ReferenceField>
|
||||
<DateField source="created_at" />
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
|
||||
export const ResponseList = () => (
|
||||
<List>
|
||||
<Datagrid>
|
||||
<ReferenceField source="user_id" reference="profiles">
|
||||
<TextField source="name" />
|
||||
</ReferenceField>
|
||||
<ReferenceField source="question_id" reference="questions">
|
||||
<TextField source="text" />
|
||||
</ReferenceField>
|
||||
<TextField source="answer" />
|
||||
<DateField source="created_at" />
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: true,
|
||||
port: 3001,
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user