# C. User Management & Profile

## Tutorial User Management & Profile

### 1. Backend User Management

#### 1.1 Role Middleware (src/middleware/role.js)

```javascript
const checkRole = (roles) => {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ message: 'Unauthorized' });
    }

    if (!roles.includes(req.user.role)) {
      return res.status(403).json({ message: 'Forbidden' });
    }

    next();
  };
};

module.exports = { checkRole };
```

#### 1.2 User Model (src/models/User.js) - Extend Existing

```javascript
const db = require('../config/database');
const bcrypt = require('bcryptjs');

const User = {
  // Existing methods dari Authentication...

  findAll: async () => {
    const [rows] = await db.execute('SELECT id, username, email, role, created_at FROM users');
    return rows;
  },

  findById: async (id) => {
    const [rows] = await db.execute('SELECT id, username, email, role, created_at FROM users WHERE id = ?', [id]);
    return rows[0];
  },

  update: async (id, userData) => {
    const { username, email } = userData;
    const [result] = await db.execute(
      'UPDATE users SET username = ?, email = ? WHERE id = ?',
      [username, email, id]
    );
    return result;
  },

  delete: async (id) => {
    const [result] = await db.execute('DELETE FROM users WHERE id = ?', [id]);
    return result;
  },

  // Methods untuk profile akan diimplementasikan nanti
  /*
  updatePassword: async (id, newPassword) => {...},
  updateAvatar: async (id, avatarUrl) => {...},
  */
};

module.exports = User;
```

#### 1.3 User Controller (src/controllers/userController.js)

```javascript
const User = require('../models/User');

const getAllUsers = async (req, res) => {
  try {
    const users = await User.findAll();
    res.json(users);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

const getUserById = async (req, res) => {
  try {
    const user = await User.findById(req.params.id);
    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }
    res.json(user);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

const updateUser = async (req, res) => {
  try {
    const result = await User.update(req.params.id, req.body);
    if (result.affectedRows === 0) {
      return res.status(404).json({ message: 'User not found' });
    }
    res.json({ message: 'User updated successfully' });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

const deleteUser = async (req, res) => {
  try {
    const result = await User.delete(req.params.id);
    if (result.affectedRows === 0) {
      return res.status(404).json({ message: 'User not found' });
    }
    res.json({ message: 'User deleted successfully' });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

module.exports = {
  getAllUsers,
  getUserById,
  updateUser,
  deleteUser
};
```

#### 1.4 User Routes (src/routes/user.routes.js)

```javascript
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const { auth } = require('../middleware/auth');
const { checkRole } = require('../middleware/role');

router.get('/', auth, checkRole(['admin']), userController.getAllUsers);
router.get('/:id', auth, checkRole(['admin', 'petugas']), userController.getUserById);
router.put('/:id', auth, checkRole(['admin']), userController.updateUser);
router.delete('/:id', auth, checkRole(['admin']), userController.deleteUser);

module.exports = router;
```

### 2. Frontend Profile Management

#### 2.1 Profile Service (src/services/profile.service.js)

```javascript
import api from './api';

const ProfileService = {
  getProfile: async () => {
    const response = await api.get('/auth/profile');
    return response.data;
  },

  updateProfile: async (data) => {
    const response = await api.put('/auth/profile', data);
    return response.data;
  },

  // Service lain akan diimplementasikan nanti
  /*
  updatePassword: async (data) => {...},
  updateAvatar: async (formData) => {...},
  */
};

export default ProfileService;
```

#### 2.2 Profile Component (src/components/profile/ProfileForm.js)

```javascript
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import ProfileService from '../../services/profile.service';

const ProfileForm = () => {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
  });
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const user = useSelector((state) => state.auth.user);

  useEffect(() => {
    if (user) {
      setFormData({
        username: user.username,
        email: user.email,
      });
    }
  }, [user]);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    try {
      await ProfileService.updateProfile(formData);
      setError(null);
    } catch (err) {
      setError(err.response?.data?.message || 'Update failed');
    } finally {
      setLoading(false);
    }
  };

  // Template akan diimplementasikan nanti
  return (
    <div>
      <h2>Profile Settings</h2>
      {/* Form akan diimplementasikan nanti */}
    </div>
  );
};

export default ProfileForm;
```

#### 2.3 User Management Components (src/components/admin/UserManagement.js)

```javascript
import React, { useState, useEffect } from 'react';
import UserService from '../../services/user.service';

const UserManagement = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      const data = await UserService.getAllUsers();
      setUsers(data);
      setError(null);
    } catch (err) {
      setError(err.response?.data?.message || 'Failed to fetch users');
    } finally {
      setLoading(false);
    }
  };

  const handleDeleteUser = async (userId) => {
    if (window.confirm('Are you sure you want to delete this user?')) {
      try {
        await UserService.deleteUser(userId);
        setUsers(users.filter(user => user.id !== userId));
      } catch (err) {
        setError(err.response?.data?.message || 'Failed to delete user');
      }
    }
  };

  // Template akan diimplementasikan nanti
  return (
    <div>
      <h2>User Management</h2>
      {/* Table dan actions akan diimplementasikan nanti */}
    </div>
  );
};

export default UserManagement;
```

#### 2.4 User Service (src/services/user.service.js)

```javascript
import api from './api';

const UserService = {
  getAllUsers: async () => {
    const response = await api.get('/users');
    return response.data;
  },

  getUserById: async (id) => {
    const response = await api.get(`/users/${id}`);
    return response.data;
  },

  updateUser: async (id, data) => {
    const response = await api.put(`/users/${id}`, data);
    return response.data;
  },

  deleteUser: async (id) => {
    const response = await api.delete(`/users/${id}`);
    return response.data;
  },
};

export default UserService;
```

**Catatan Implementasi:**

1. Frontend Components yang perlu dibuat:
   * Profile settings page
   * Change password form
   * Avatar upload component
   * User list table
   * User edit modal
   * Role management interface
2. Backend Features yang perlu ditambahkan:
   * Password change functionality
   * Avatar upload handling
   * User search dan filtering
   * Pagination untuk user list
   * Advanced role permissions
3. Security Considerations:
   * Validasi input untuk semua forms
   * Sanitasi data sebelum menyimpan ke database
   * File upload restrictions
   * Role-based access control yang ketat
4. Additional Features untuk diimplementasikan:
   * User activity logs
   * Last login tracking
   * Session management
   * Email notifications untuk password changes
   * Two-factor authentication

Untuk testing:

1. Test CRUD operations untuk users
2. Verify role-based access
3. Test profile updates
4. Validate file uploads
5. Check error handling
6. Test form validations


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://triyono.gitbook.io/tutorial/full-stack-web-mysql-express-react-node-js/getting-started/c.-user-management-and-profile.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
