seting up dev vs prod enviroment

This commit is contained in:
dimitar 2025-04-05 01:39:25 +02:00
parent 275a7873d2
commit 88f20bbb3b
30 changed files with 451 additions and 277 deletions

View File

@ -1,34 +0,0 @@
You are a Senior full-stack Developer and an Expert in Nestjs, Prisma,ReactJS, JavaScript, TypeScript, HTML, CSS and modern UI/UX frameworks (e.g., TailwindCSS, Shadcn, Radix). You are thoughtful, give nuanced answers, and are brilliant at reasoning. You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning.
- Follow the users requirements carefully & to the letter.
- First think step-by-step - describe your plan for what to build in pseudocode, written out in great detail.
- Confirm, then write code!
- Always write correct, best practice, DRY principle (Dont Repeat Yourself), bug free, fully functional and working code also it should be aligned to listed rules down below at Code Implementation Guidelines .
- Focus on easy and readability code, over being performant.
- Fully implement all requested functionality.
- Leave NO todos, placeholders or missing pieces.
- Ensure code is complete! Verify thoroughly finalised.
- Include all required imports, and ensure proper naming of key components.
- Be concise Minimize any other prose.
- If you think there might not be a correct answer, you say so.
- If you do not know the answer, say so, instead of guessing.
### Coding Environment
The user asks questions about the following coding languages:
- ReactJS
- Nestjs
- Prisma
- JavaScript
- TypeScript
- TailwindCSS
- HTML
- CSS
### Code Implementation Guidelines
Follow these rules when you write code:
- Use early returns whenever possible to make the code more readable.
- Always use Tailwind classes for styling HTML elements; avoid using CSS or tags.
- Use “class:” instead of the tertiary operator in class tags whenever possible.
- Use descriptive variable and function/const names. Also, event functions should be named with a “handle” prefix, like “handleClick” for onClick and “handleKeyDown” for onKeyDown.
- Implement accessibility features on elements. For example, a tag should have a tabindex=“0”, aria-label, on:click, and on:keydown, and similar attributes.
- Use consts instead of functions, for example, “const toggle = () =>”. Also, define a type if possible.

2
.gitignore vendored
View File

@ -9,4 +9,4 @@ frontend/.vite
node_modules node_modules
pestgres_data/ pestgres_data/
redis_data/ redis_data/
aisugestions.md

70
Dockerfile Normal file
View File

@ -0,0 +1,70 @@
# backend/Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
# Install necessary tools
RUN apk add --no-cache curl wget postgresql-client
# Copy package files
COPY package*.json ./
# Install dependencies including dev dependencies for building
RUN npm install
# Install NestJS CLI globally
RUN npm install -g @nestjs/cli
# Copy prisma files
COPY prisma ./prisma/
# Generate Prisma client
RUN npx prisma generate
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Production stage
FROM node:18-alpine
WORKDIR /app
# Install necessary tools
RUN apk add --no-cache curl wget postgresql-client
# Copy package files
COPY package*.json ./
# Install production dependencies only
RUN npm install --omit=dev
# Copy prisma files and generate client
COPY prisma ./prisma/
RUN npx prisma generate
# Copy built application from builder stage
COPY --from=builder /app/dist ./dist
# Create the start script
RUN printf '#!/bin/sh\n\
until pg_isready -h postgres -p 5432 -U ${POSTGRES_USER} -d ${POSTGRES_DB}; do\n\
echo "Waiting for postgres..."\n\
sleep 2\n\
done\n\
\n\
echo "PostgreSQL is ready!"\n\
\n\
npx prisma migrate deploy\n\
node dist/main.js\n' > /app/start.sh
# Make the script executable
RUN chmod +x /app/start.sh
EXPOSE 3000
# Use shell form to ensure environment variables are expanded
CMD ["/bin/sh", "/app/start.sh"]

13
TODO.md Normal file
View File

@ -0,0 +1,13 @@
# Todo
- [ ] on password reset page, link in the sent to user email is undefined;
- [ ] translate mail template in backend;
- [x] translate user dashboard;
- [ ] clean console logs;
- [ ] remove TUF logo;
- [ ] arrow down fix;
- [ ] use posthog for monitoring;
- [ ] comprehensive monitoring solution for the backend;
- [ ] add monitoring to the frontend;
- [ ] add monitoring to the database;
- [ ]

35
_.env
View File

@ -1,35 +0,0 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://root:irina76@localhost:5433/imk2?schema=public"
JWT_SECRET=some-secret
AWS_REGION=EU2
AWS_ACCESS_KEY_ID=4d2f5655369a02100375e3247d7e1fe6
AWS_SECRET_ACCESS_KEY=6d4723e14c0d799b89948c24dbe983e4
AWS_S3_BUCKET_NAME=imk-data
AWS_ENDPOINT_URL=https://eu2.contabostorage.com
#Email Configuration
# SMTP_HOST=smtp.gmail.com
# SMTP_PORT=587
# SMTP_USER=taratur@gmail.com
# SMTP_PASS=dziy nccc svgg bovb
# EMAIL_FROM=taratur@gmail.com
SMTP_HOST=imk.mk
SMTP_PORT=465
SMTP_USER=mailer@imk.mk
SMTP_PASS=76Avtostoperski76
SMTP_FROM=mailer@imk.mk
# FRONTEND_URL=https://imk.mk
EMAIL_FROM=mailer@yandex.com
ADMIN_EMAIL=taratur@gmail.com
# default app ADMIN
DEFAULT_ADMIN_EMAIL=taratur@gmail.com
DEFAULT_ADMIN_PASSWORD=irina7654321
DEFAULT_ADMIN_NAME=admin

View File

@ -1,97 +0,0 @@
version: "3.8"
services:
backend:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
container_name: imk-backend
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- DATABASE_URL=postgresql://postgres:postgres@imk-postgres:5432/postgres?schema=public
- FRONTEND_URL=https://www.placebo.mk
env_file:
- .env
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 512M
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
networks:
- app_network
healthcheck:
test:
[
"CMD",
"wget",
"-q",
"--spider",
"http://localhost:3000/health || exit 1",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
restart: always
postgres:
container_name: imk-postgres
image: postgres:14-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app_network
restart: always
redis:
container_name: imk-redis
image: redis:alpine
command: redis-server --appendonly yes
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- app_network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
restart: always
networks:
app_network:
driver: bridge
name: app_network
volumes:
postgres_data:
name: imk_postgres_data
redis_data:
name: imk_redis_data

View File

@ -1,6 +1,6 @@
# backend/.dockerignore # backend/.dockerignore
node_modules node_modules
dist dist
.env #.env
.env.* #.env.*
*.log *.log

33
backend/Dockerfile.dev Normal file
View File

@ -0,0 +1,33 @@
FROM node:18-alpine
WORKDIR /app
# Install necessary tools
RUN apk add --no-cache \
curl \
wget \
postgresql-client \
bash
# Install global packages
RUN npm install -g @nestjs/cli
# Copy scripts
COPY scripts/start-dev.sh /app/scripts/
RUN chmod +x /app/scripts/start-dev.sh
COPY package.json package-lock.json ./
RUN npm install
# Copy prisma files
COPY prisma ./prisma/
# Generate Prisma client
RUN npx prisma generate
EXPOSE 3000 9229
# Use the initialization script as the entry point
CMD ["/app/scripts/start-dev.sh"]

View File

@ -1,76 +0,0 @@
# backend/Dockerfile
FROM node:18-alpine
# Add build arguments
ARG NODE_ENV
ARG API_URL
ARG CORS_ORIGIN
ARG DATABASE_URL
ARG POSTGRES_USER
ARG POSTGRES_PASSWORD
ARG POSTGRES_DB
ARG JWT_SECRET
ARG SMTP_HOST
ARG SMTP_PORT
ARG SMTP_USER
ARG SMTP_PASS
ARG EMAIL_FROM
ARG DEFAULT_ADMIN_EMAIL
ARG DEFAULT_ADMIN_PASSWORD
ARG DEFAULT_ADMIN_NAME
# Set environment variables from build args
ENV NODE_ENV=${NODE_ENV}
ENV API_URL=${API_URL}
ENV CORS_ORIGIN=${CORS_ORIGIN}
ENV DATABASE_URL=${DATABASE_URL}
ENV POSTGRES_USER=${POSTGRES_USER}
ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ENV POSTGRES_DB=${POSTGRES_DB}
ENV JWT_SECRET=${JWT_SECRET}
ENV SMTP_HOST=${SMTP_HOST}
ENV SMTP_PORT=${SMTP_PORT}
ENV SMTP_USER=${SMTP_USER}
ENV SMTP_PASS=${SMTP_PASS}
ENV EMAIL_FROM=${EMAIL_FROM}
ENV DEFAULT_ADMIN_EMAIL=${DEFAULT_ADMIN_EMAIL}
ENV DEFAULT_ADMIN_PASSWORD=${DEFAULT_ADMIN_PASSWORD}
ENV DEFAULT_ADMIN_NAME=${DEFAULT_ADMIN_NAME}
WORKDIR /usr/src/app
# Install necessary tools
RUN apk add --no-cache curl wget postgresql-client
# Copy package files
COPY package*.json ./
COPY prisma ./prisma/
# Install dependencies
RUN npm install --omit-dev
# Copy prisma schema
# COPY prisma ./prisma/
# Generate Prisma client
RUN npx prisma generate
# RUN npx prisma migrate deploy
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Expose port
EXPOSE 3000
# ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /wait-for-it.sh
# RUN chmod +x /wait-for-it.sh
# Add healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD wget -q --spider http://localhost:3000/health || exit 1
# Start the application
# CMD ["npm", "run", "start:prod"]
CMD ["node", "dist/main.js"]

View File

@ -0,0 +1,75 @@
version: "3.8"
services:
postgres:
container_name: imk-postgres-dev
image: postgres:14-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: imk_db
volumes:
- postgres_data_dev:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- imk_network_dev
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
backend:
container_name: imk-backend-dev
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app/src:delegated
- ./prisma:/app/prisma:delegated
- ./package.json:/app/package.json:delegated
- ./package-lock.json:/app/package-lock.json:delegated
- ./tsconfig.json:/app/tsconfig.json:delegated
- ./nest-cli.json:/app/nest-cli.json:delegated
- node_modules:/app/node_modules
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/imk_db?schema=public
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=imk_db
- JWT_SECRET=${JWT_SECRET}
- AWS_REGION=${AWS_REGION}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME}
- AWS_ENDPOINT_URL=${AWS_ENDPOINT_URL}
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_USER=${SMTP_USER}
- SMTP_PASS=${SMTP_PASS}
- EMAIL_FROM=${EMAIL_FROM}
- FRONTEND_URL=${FRONTEND_URL}
ports:
- "3000:3000"
- "9229:9229"
depends_on:
postgres:
condition: service_healthy
networks:
- imk_network_dev
restart: unless-stopped
command: ["/app/scripts/start-dev.sh"]
tty: true
stdin_open: true
# command: sh -c "rm -rf /app/dist && npm run start:dev"
networks:
imk_network_dev:
driver: bridge
volumes:
postgres_data_dev:
node_modules:

34
backend/env.development Normal file
View File

@ -0,0 +1,34 @@
# imk_copy/backend/.env.development
# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=imk_dev
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/imk_dev?schema=public
# JWT
JWT_SECRET=your_development_jwt_secret
# AWS/S3
AWS_REGION=your-region
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_S3_BUCKET_NAME=your-bucket-name
AWS_ENDPOINT_URL=your-endpoint-url
# SMTP
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-smtp-user
SMTP_PASS=your-smtp-password
EMAIL_FROM=noreply@example.com
# Frontend
FRONTEND_URL=http://localhost:5173
# Admin defaults
DEFAULT_ADMIN_EMAIL=admin@example.com
DEFAULT_ADMIN_PASSWORD=admin123
DEFAULT_ADMIN_NAME=System Admin
# Node
NODE_ENV=development

View File

@ -23,7 +23,10 @@
"test:e2e": "jest --config ./test/jest-e2e.json", "test:e2e": "jest --config ./test/jest-e2e.json",
"prisma:generate": "prisma generate", "prisma:generate": "prisma generate",
"prisma:migrate:dev": "prisma migrate dev", "prisma:migrate:dev": "prisma migrate dev",
"prisma:migrate": "prisma migrate deploy" "prisma:migrate": "prisma migrate deploy",
"docker:dev": "docker-compose -f docker-compose.dev.yml up",
"docker:dev:build": "docker-compose -f docker-compose.dev.yml up --build",
"docker:dev:down": "docker-compose -f docker-compose.dev.yml down -v"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.679.0", "@aws-sdk/client-s3": "^3.679.0",

View File

@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "_SharedDocuments" ADD CONSTRAINT "_SharedDocuments_AB_pkey" PRIMARY KEY ("A", "B");
-- DropIndex
DROP INDEX "_SharedDocuments_AB_unique";

View File

@ -1,3 +1,3 @@
# Please do not edit this file manually # Please do not edit this file manually
# It should be added in your version-control system (i.e. Git) # It should be added in your version-control system (e.g., Git)
provider = "postgresql" provider = "postgresql"

9
backend/scripts/_init-db.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
# backend/scripts/init-db.sh
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE DATABASE $POSTGRES_DB;
GRANT ALL PRIVILEGES ON DATABASE $POSTGRES_DB TO $POSTGRES_USER;
EOSQL

29
backend/scripts/init-db.sh Normal file → Executable file
View File

@ -1,9 +1,24 @@
#!/bin/bash #!/bin/sh
# backend/scripts/init-db.sh
set -e echo "Starting development initialization..."
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL # Wait for database to be ready
CREATE DATABASE $POSTGRES_DB; echo "Waiting for database to be ready..."
GRANT ALL PRIVILEGES ON DATABASE $POSTGRES_DB TO $POSTGRES_USER; until PGPASSWORD=$POSTGRES_PASSWORD psql -h postgres -U $POSTGRES_USER -d postgres -c '\q'; do
EOSQL echo "Postgres is unavailable - sleeping"
sleep 1
done
echo "Database is ready!"
# Run Prisma migrations
echo "Running Prisma migrations..."
npx prisma migrate dev
# Generate Prisma Client (just in case)
echo "Generating Prisma Client..."
npx prisma generate
# Start the application
echo "Starting application in development mode..."
npm run start:dev

20
backend/scripts/init-dev.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
echo "Starting development server..."
# Wait for database to be ready
echo "Waiting for database to be ready..."
until PGPASSWORD=$POSTGRES_PASSWORD psql -h postgres -U $POSTGRES_USER -d postgres -c '\q'; do
echo "Postgres is unavailable - sleeping"
sleep 1
done
echo "Database is ready!"
# Run Prisma migrations
echo "Running Prisma migrations..."
npx prisma migrate dev --name init
# Start the application
echo "Starting application..."
npm run start:dev

30
backend/scripts/start-dev.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/sh
echo "Starting development initialization..."
# Wait for database to be ready
echo "Waiting for database to be ready..."
until PGPASSWORD=$POSTGRES_PASSWORD psql -h postgres -U $POSTGRES_USER -d postgres -c '\q'; do
echo "Postgres is unavailable - sleeping"
sleep 1
done
echo "Database is ready!"
# Run Prisma migrations
echo "Running Prisma migrations..."
npx prisma migrate dev --name init
# Generate Prisma Client (just in case)
echo "Generating Prisma Client..."
npx prisma generate
# Clean dist directory if it exists
if [ -d "dist" ]; then
echo "Cleaning dist directory..."
rm -rf dist
fi
# Start the application in development mode
echo "Starting application in development mode..."
exec npm run start:dev

0
backend/scripts/test-db.sh Normal file → Executable file
View File

0
backend/scripts/wait-for-db.sh Normal file → Executable file
View File

View File

@ -1,9 +1,9 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from "@nestjs/testing";
import { AuthController } from './auth.controller'; import { AuthController } from "./auth.controller";
import { AuthService } from './auth.service'; import { AuthService } from "./auth.service";
import { CreateUserDto } from '../dto/create-user.dto'; import { CreateUserDto } from "../dto/create-user.dto";
describe('AuthController', () => { describe("AuthController", () => {
let controller: AuthController; let controller: AuthController;
let authService: AuthService; let authService: AuthService;
@ -24,12 +24,13 @@ describe('AuthController', () => {
authService = module.get<AuthService>(AuthService); authService = module.get<AuthService>(AuthService);
}); });
describe('register', () => { describe("register", () => {
it('should call authService.createUser with CreateUserDto', async () => { it("should call authService.createUser with CreateUserDto", async () => {
const createUserDto: CreateUserDto = { const createUserDto: CreateUserDto = {
name: 'testuser', name: "testuser",
password: 'password123', password: "password123",
email: 'test@example.com', email: "test@example.com",
isAdmin: false,
}; };
await controller.register(createUserDto); await controller.register(createUserDto);

View File

@ -4,9 +4,9 @@ export const corsConfig = {
"https://www.placebo.mk", "https://www.placebo.mk",
"https://placebo.mk", "https://placebo.mk",
"https://imkapi.oblak.solutions", "https://imkapi.oblak.solutions",
"https://eu-assets.i.posthog.com", // "https://eu-assets.i.posthog.com",
"https://app.posthog.com", // "https://app.posthog.com",
"https://eu.posthog.com", // "https://eu.posthog.com",
], ],
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"], methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
credentials: true, credentials: true,

View File

@ -1,5 +1,5 @@
import { IsString, IsEmail, MinLength, IsBoolean } from 'class-validator'; import { IsString, IsEmail, MinLength, IsBoolean } from "class-validator";
import { Transform } from 'class-transformer'; import { Transform } from "class-transformer";
export class CreateUserDto { export class CreateUserDto {
@IsString() @IsString()

View File

@ -25,6 +25,12 @@ async function bootstrap() {
whitelist: true, whitelist: true,
}), }),
); );
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
}),
);
app.use( app.use(
helmet({ helmet({
@ -69,7 +75,7 @@ async function bootstrap() {
logger.log(`Attempting to start server on port ${port}...`); logger.log(`Attempting to start server on port ${port}...`);
await app.listen(port, "0.0.0.0"); await app.listen(port, "0.0.0.0");
logger.log(`Application is running on: ${await app.getUrl()}`); logger.log(`Application is Running on: ${await app.getUrl()}`);
} catch (error) { } catch (error) {
logger.error("Failed to start application:", error); logger.error("Failed to start application:", error);
process.exit(1); process.exit(1);

11
backend/start-dev.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
until pg_isready -h postgres -p 5432 -U ${POSTGRES_USER} -d ${POSTGRES_DB}; do
echo "Waiting for postgres..."
sleep 2
done
echo "PostgreSQL is ready!"
npx prisma migrate dev --name init
npm run start:dev

47
docker-compose.yaml Normal file
View File

@ -0,0 +1,47 @@
version: "3.8"
services:
backend:
container_name: imk-backend
build:
context: .
dockerfile: Dockerfile
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=public
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
ports:
- "3000:3000"
depends_on:
postgres:
condition: service_healthy
networks:
- imk_network
postgres:
container_name: imk-postgres
image: postgres:14-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5433:5432"
networks:
- imk_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
imk_network:
driver: bridge
volumes:
postgres_data:

View File

@ -12,3 +12,20 @@ docker rmi -f $(docker images -q)
# Start fresh # Start fresh
docker-compose up --build docker-compose up --build
# reset development
# Stop containers and remove volumes
docker-compose -f docker-compose.dev.yml down -v
# Remove existing images
docker rmi $(docker images -q backend_backend)
# Rebuild and start
docker-compose -f docker-compose.dev.yml up --build
docker-compose -f docker-compose.dev.yml up --build --force-recreate

View File

@ -7,7 +7,7 @@ import { Card } from "../UI/Card";
function DocumentUpload() { function DocumentUpload() {
const [file, setFile] = useState(null); const [file, setFile] = useState(null);
const [title, setTitle] = useState(""); const [title, setTitle] = useState("");
const [selectedUserId, setSelectedUserId] = useState(""); // Changed from array to single value const [selectedUserId, setSelectedUserId] = useState("");
const [availableUsers, setAvailableUsers] = useState([]); const [availableUsers, setAvailableUsers] = useState([]);
const [status, setStatus] = useState("idle"); const [status, setStatus] = useState("idle");
const [errorMessage, setErrorMessage] = useState(""); const [errorMessage, setErrorMessage] = useState("");

View File

@ -1,13 +1,38 @@
import react from "react";
import { useState } from "react"; import { useState } from "react";
import {
getAllUsers,
getUserInfo,
createUser,
resetUserPassword,
} from "../../services/api";
import { useNavigate } from "react-router-dom";
import { FiKey, FiUserPlus } from "react-icons/fi";
function Users() { function Users() {
const [newUser, setNewUser] = useState({}); const navigate = useNavigate();
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const [resetPasswordModal, setResetPasswordModal] = useState({
isOpen: false,
userId: null,
userName: "",
newPassword: "",
});
const [newUser, setNewUser] = useState({
name: "",
email: "",
password: "",
isAdmin: false,
});
return ( return (
<> <div>
<div className="bg-primary-800/50 backdrop-blur-lg rounded-xl p-6 mb-6 shadow-xl"> <div className="bg-primary-800/50 backdrop-blur-lg rounded-xl p-6 mb-6 shadow-xl">
<h2 className="text-xl font-bold text-white mb-4">Креирај корисник</h2> <h2 className="text-xl font-bold text-white mb-4">Креирај корисник</h2>
<form <form
ref={createUserFormRef}
onSubmit={handleCreateUser} onSubmit={handleCreateUser}
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4" className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"
> >
@ -131,6 +156,7 @@ function Users() {
</tbody> </tbody>
</table> </table>
</div> </div>
</> </div>
); );
} }
export default Users;

View File

@ -1,8 +1,9 @@
import axios from "axios"; import axios from "axios";
const API_URL = "https://imkapi.oblak.solutions:3000"; // const API_URL = "https://imkapi.oblak.solutions:3000";
const API_URL = "https://localhost:3000";
const api = axios.create({ const api = axios.create({
baseURL: "https://imkapi.oblak.solutions", baseURL: API_URL,
withCredentials: true, withCredentials: true,
headers: { headers: {
Accept: "application/json, text/plain, */*", Accept: "application/json, text/plain, */*",